iBATIS - SQL dinamico

Dynamic SQL è una funzionalità molto potente di iBATIS. A volte è necessario modificare il criterio della clausola WHERE in base allo stato dell'oggetto parametro. In tali situazioni, iBATIS fornisce una serie di tag SQL dinamici che possono essere utilizzati all'interno di istruzioni mappate per migliorare la riutilizzabilità e la flessibilità dell'SQL.

Tutta la logica viene inserita nel file .XML utilizzando alcuni tag aggiuntivi. Di seguito è riportato un esempio in cui l'istruzione SELECT funzionerebbe in due modi:

  • Se si passa un ID, verranno restituiti tutti i record corrispondenti a tale ID.
  • In caso contrario, restituirà tutti i record in cui l'ID dipendente è impostato su 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>

È possibile verificare una condizione utilizzando il tag <isNotEmpty> come segue. Qui una condizione verrebbe aggiunta solo quando una proprietà passata non è vuota.

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

Se desideri una query in cui possiamo selezionare un ID e / o il nome di un dipendente, la tua istruzione SELECT sarà la seguente:

..................
<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>
..................

Esempio SQL dinamico

L'esempio seguente mostra come scrivere un'istruzione SELECT con SQL dinamico. Considera, abbiamo la seguente tabella EMPLOYEE in 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)
);

Supponiamo che questa tabella abbia un solo record come segue:

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

Classe POJO dei dipendenti

Per eseguire l'operazione di lettura, disponiamo di una classe Employee in Employee.java come segue:

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 */

File Employee.xml

Per definire l'istruzione di mappatura SQL utilizzando iBATIS, aggiungeremmo il seguente tag <select> modificato in Employee.xml e all'interno di questa definizione di tag, definiremmo un "id" che verrà utilizzato in IbatisReadDy.java per eseguire query SQL SELECT dinamico su Banca dati.

<?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>

L'istruzione SELECT di cui sopra funzionerebbe in due modi:

  • Se si passa un ID, restituisce i record corrispondenti a quell'ID. Altrimenti, restituisce tutti i record.

File IbatisReadDy.java

Questo file ha una logica a livello di applicazione per leggere i record condizionali dalla tabella 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 ");
   }
}

Compilazione ed esecuzione

Ecco i passaggi per compilare ed eseguire il software sopra menzionato. Assicurati di aver impostato PATH e CLASSPATH in modo appropriato prima di procedere con la compilazione e l'esecuzione.

  • Crea Employee.xml come mostrato sopra.
  • Crea Employee.java come mostrato sopra e compilarlo.
  • Crea IbatisReadDy.java come mostrato sopra e compilarlo.
  • Esegui il binario IbatisReadDy per eseguire il programma.

Si otterrebbe il seguente risultato e verrà letto un record dalla tabella EMPLOYEE.

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

Prova l'esempio sopra passando nullcome smc.queryForList ("Employee.findByID", null) .

Espressioni iBATIS OGNL

iBATIS fornisce potenti espressioni basate su OGNL per eliminare la maggior parte degli altri elementi.

  • if Statement
  • scegli, quando, altrimenti Statement
  • where Statement
  • Istruzione foreach

L'istruzione if

La cosa più comune da fare in SQL dinamico è includere in modo condizionale una parte di una clausola where. Ad esempio:

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

Questa istruzione fornisce un tipo di funzionalità di ricerca di testo opzionale. Se non passi nessun titolo, vengono restituiti tutti i blog attivi. Ma se passi un titolo, cercherà un titolo con il datolike condizione.

Puoi includere più file if condizioni come 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>

La scelta, quando e altrimenti Dichiarazioni

iBATIS offre un chooseelemento che è simile all'istruzione switch di Java. Aiuta a scegliere solo un caso tra molte opzioni.

Il seguente esempio cercherà solo per titolo se ne viene fornito uno, quindi solo per autore se ne viene fornito uno. Se nessuno dei due viene fornito, restituisce solo i blog in primo piano -

<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>

L'istruzione where

Dai un'occhiata ai nostri esempi precedenti per vedere cosa succede se nessuna delle condizioni è soddisfatta. Ti ritroveresti con un SQL simile a questo -

SELECT * FROM BLOG
WHERE

Questo fallirebbe, ma iBATIS ha una soluzione semplice con una semplice modifica, tutto funziona bene -

<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>

Il wherel'elemento inserisce un WHERE solo quando i tag contenitore restituiscono qualsiasi contenuto. Inoltre, se quel contenuto inizia con AND o OR, sa di rimuoverlo.

La dichiarazione foreach

L'elemento foreach consente di specificare una raccolta e di dichiarare variabili di elemento e indice che possono essere utilizzate all'interno del corpo dell'elemento.

Consente inoltre di specificare stringhe di apertura e chiusura e di aggiungere un separatore da inserire tra le iterazioni. Puoi costruire un fileIN condizione come segue -

<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>