iBATIS - SQL Dinâmico

SQL dinâmico é um recurso muito poderoso do iBATIS. Às vezes, você precisa alterar o critério da cláusula WHERE com base no estado do seu objeto de parâmetro. Em tais situações, o iBATIS fornece um conjunto de tags SQL dinâmicas que podem ser usadas em instruções mapeadas para aprimorar a capacidade de reutilização e flexibilidade do SQL.

Toda a lógica é colocada em um arquivo .XML usando algumas tags adicionais. A seguir está um exemplo em que a instrução SELECT funcionaria de duas maneiras -

  • Se você passar um ID, ele retornará todos os registros correspondentes a esse ID.
  • Caso contrário, ele retornaria todos os registros onde o ID do funcionário está definido como NULL.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">

<sqlMap namespace="Employee">

   <select id="findByID" resultClass="Employee">
      SELECT * FROM EMPLOYEE
		
      <dynamic prepend="WHERE ">
         <isNull property="id">
            id IS NULL
         </isNull>
			
         <isNotNull property="id">
            id = #id#
         </isNotNull>
      </dynamic>
		
   </select>
</sqlMap>

Você pode verificar uma condição usando a tag <isNotEmpty> da seguinte maneira. Aqui, uma condição seria adicionada apenas quando uma propriedade passada não estivesse vazia.

..................
<select id="findByID" resultClass="Employee">
   SELECT * FROM EMPLOYEE
	
   <dynamic prepend="WHERE ">
      <isNotEmpty property="id">
         id = #id#
      </isNotEmpty>
   </dynamic>
	
</select>
..................

Se você quiser uma consulta em que possamos selecionar um id e / ou o primeiro nome de um funcionário, sua instrução SELECT seria a seguinte -

..................
<select id="findByID" resultClass="Employee">
   SELECT * FROM EMPLOYEE
	
   <dynamic prepend="WHERE ">
      <isNotEmpty prepend="AND" property="id">
         id = #id#
      </isNotEmpty>
		
      <isNotEmpty prepend="OR" property="first_name">
         first_name = #first_name#
      </isNotEmpty>
   </dynamic>
</select>
..................

Exemplo de SQL Dinâmico

O exemplo a seguir mostra como você pode escrever uma instrução SELECT com SQL dinâmico. Considere, temos a seguinte tabela EMPLOYEE no MySQL -

CREATE TABLE EMPLOYEE (
   id INT NOT NULL auto_increment,
   first_name VARCHAR(20) default NULL,
   last_name  VARCHAR(20) default NULL,
   salary     INT  default NULL,
   PRIMARY KEY (id)
);

Vamos supor que esta tabela tenha apenas um registro da seguinte forma -

mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
|  1 | Zara       | Ali       |   5000 |
+----+------------+-----------+--------+
1 row in set (0.00 sec)

Classe POJO do funcionário

Para realizar a operação de leitura, vamos ter uma classe Employee em Employee.java da seguinte maneira -

public class Employee {
   private int id;
   private String first_name; 
   private String last_name;   
   private int salary;  

   /* Define constructors for the Employee class. */
   public Employee() {}
  
   public Employee(String fname, String lname, int salary) {
      this.first_name = fname;
      this.last_name = lname;
      this.salary = salary;
   }

   /* Here are the method definitions */
   public int getId() {
      return id;
   }
	
   public String getFirstName() {
      return first_name;
   }
	
   public String getLastName() {
      return last_name;
   }
	
   public int getSalary() {
      return salary;
   }
	
} /* End of Employee */

Arquivo Employee.xml

Para definir a instrução de mapeamento SQL usando iBATIS, adicionaríamos a seguinte tag <select> modificada em Employee.xml e dentro dessa definição de tag, definiríamos um "id" que será usado em IbatisReadDy.java para executar a consulta SQL SELECT dinâmica em base de dados.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">

<sqlMap namespace="Employee">
   <select id="findByID" resultClass="Employee">
      SELECT * FROM EMPLOYEE
	
      <dynamic prepend="WHERE ">
         <isNotNull property="id">
            id = #id#
         </isNotNull>
      </dynamic>
		
   </select>
</sqlMap>

A instrução SELECT acima funcionaria de duas maneiras -

  • Se você passar um ID, ele retorna os registros correspondentes a esse ID. Caso contrário, ele retorna todos os registros.

Arquivo IbatisReadDy.java

Este arquivo tem lógica de nível de aplicativo para ler registros condicionais da tabela Employee -

import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;

import java.io.*;
import java.sql.SQLException;
import java.util.*;

public class IbatisReadDy{
   public static void main(String[] args) throws IOException,SQLException{
   
      Reader rd=Resources.getResourceAsReader("SqlMapConfig.xml");
      SqlMapClient smc=SqlMapClientBuilder.buildSqlMapClient(rd);

      /* This would read all records from the Employee table.*/
      System.out.println("Going to read records.....");
      Employee rec = new Employee();
      rec.setId(1);

      List <Employee> ems = (List<Employee>)  
         smc.queryForList("Employee.findByID", rec);
      Employee em = null;
		
      for (Employee e : ems) {
         System.out.print("  " + e.getId());
         System.out.print("  " + e.getFirstName());
         System.out.print("  " + e.getLastName());
         System.out.print("  " + e.getSalary());
         em = e; 
         System.out.println("");
      }    
      System.out.println("Records Read Successfully ");
   }
}

Compilação e execução

Aqui estão as etapas para compilar e executar o software mencionado acima. Certifique-se de definir PATH e CLASSPATH apropriadamente antes de prosseguir com a compilação e execução.

  • Crie Employee.xml conforme mostrado acima.
  • Crie Employee.java conforme mostrado acima e compile-o.
  • Crie IbatisReadDy.java conforme mostrado acima e compile-o.
  • Execute o binário IbatisReadDy para executar o programa.

Você obteria o seguinte resultado e um registro seria lido da tabela EMPLOYEE.

Going to read records.....
   1  Zara  Ali  5000
Record Reads Successfully

Experimente o exemplo acima passando nullcomo smc.queryForList ("Employee.findByID", null) .

Expressões iBATIS OGNL

O iBATIS fornece expressões baseadas em OGNL poderosas para eliminar a maioria dos outros elementos.

  • declaração if
  • escolher, quando, de outra forma Declaração
  • onde declaração
  • declaração foreach

A declaração if

A coisa mais comum a se fazer em SQL dinâmico é incluir condicionalmente uma parte de uma cláusula where. Por exemplo -

<select id="findActiveBlogWithTitleLike" parameterType="Blog" resultType="Blog">
   SELECT * FROM BLOG
   WHERE state = 'ACTIVE.
	
   <if test="title != null">
      AND title like #{title}
   </if>
	
</select>

Esta declaração fornece um tipo de funcionalidade de pesquisa de texto opcional. Se você não transmitir nenhum título, todos os blogs ativos serão retornados. Mas se você passar um título, ele irá procurar por um título com o dadolike doença.

Você pode incluir vários if condições como segue -

<select id="findActiveBlogWithTitleLike" parameterType="Blog" resultType="Blog">
   SELECT * FROM BLOG
   WHERE state = 'ACTIVE.
	
   <if test="title != null">
      AND title like #{title}
   </if>
	
   <if test="author != null">
      AND author like #{author}
   </if>
	
</select>

A escolha, quando e outras declarações

iBATIS oferece um chooseelemento que é semelhante à instrução switch do Java. Ajuda a escolher apenas um caso entre muitas opções.

O exemplo a seguir pesquisaria apenas por título, se fornecido, e apenas por autor, se fornecido. Se nenhum dos dois for fornecido, ele retornará apenas blogs em destaque -

<select id="findActiveBlogWithTitleLike" parameterType="Blog" resultType="Blog">
   SELECT * FROM BLOG
   WHERE state = 'ACTIVE.
	
   <choose>
      <when test="title != null">
         AND title like #{title}
      </when>
		
      <when test="author != null and author.name != null">
         AND author like #{author}
      </when>
		
      <otherwise>
         AND featured = 1
      </otherwise>
   </choose>
	
</select>

A declaração onde

Dê uma olhada em nossos exemplos anteriores para ver o que acontece se nenhuma das condições for atendida. Você acabaria com um SQL parecido com este -

SELECT * FROM BLOG
WHERE

Isso falharia, mas o iBATIS tem uma solução simples com uma mudança simples, tudo funciona bem -

<select id="findActiveBlogLike" parameterType="Blog" resultType="Blog">
   SELECT * FROM BLOG
	
   <where>
      <if test="state != null">
         state = #{state}
      </if>
		
      <if test="title != null">
         AND title like #{title}
      </if>
		
      <if test="author != null>
         AND author like #{author}
      </if>
   </where>
	
</select>

o whereelemento insere um WHERE apenas quando as tags que o contêm retornam qualquer conteúdo. Além disso, se esse conteúdo começar com AND ou OR, ele saberá como removê-lo.

A declaração foreach

O elemento foreach permite que você especifique uma coleção e declare as variáveis ​​de item e índice que podem ser usadas dentro do corpo do elemento.

Ele também permite especificar strings de abertura e fechamento e adicionar um separador para colocar entre as iterações. Você pode construir umIN condição da seguinte forma -

<select id="selectPostIn" resultType="domain.blog.Post">
   SELECT *
   FROM POST P
   WHERE ID in
	
   <foreach item="item" index="index" collection="list"
      open="(" separator="," close=")">
      #{item}
   </foreach>
	
</select>