iBATIS - Dynamiczny SQL

Dynamiczny SQL to bardzo potężna funkcja iBATIS. Czasami trzeba zmienić kryterium klauzuli WHERE na podstawie stanu obiektu parametru. W takich sytuacjach iBATIS zapewnia zestaw dynamicznych znaczników SQL, których można używać w mapowanych instrukcjach w celu zwiększenia możliwości ponownego wykorzystania i elastyczności SQL.

Cała logika jest umieszczona w pliku .XML za pomocą dodatkowych tagów. Poniżej znajduje się przykład, w którym instrukcja SELECT działałaby na dwa sposoby:

  • Jeśli przekażesz identyfikator, zwróci on wszystkie rekordy odpowiadające temu identyfikatorowi.
  • W przeciwnym razie zwróciłoby wszystkie rekordy, w których identyfikator pracownika ma wartość 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>

Możesz sprawdzić warunek za pomocą tagu <isNotEmpty> w następujący sposób. Tutaj warunek zostałby dodany tylko wtedy, gdy przekazana właściwość nie jest pusta.

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

Jeśli potrzebujesz zapytania, w którym możemy wybrać identyfikator i / lub imię pracownika, Twoja instrukcja SELECT wyglądałaby następująco:

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

Przykład dynamicznego SQL

Poniższy przykład pokazuje, jak można napisać instrukcję SELECT za pomocą dynamicznego języka SQL. Rozważmy, że w MySQL mamy następującą tabelę PRACOWNIKÓW -

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

Załóżmy, że ta tabela ma tylko jeden rekord w następujący sposób -

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

Klasa pracownicza POJO

Aby wykonać operację odczytu, przygotujmy klasę Employee na Employee.java w następujący sposób -

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

Plik Employee.xml

Aby zdefiniować instrukcję mapowania SQL za pomocą iBATIS, dodalibyśmy następujący zmodyfikowany tag <select> w pliku Employee.xml i wewnątrz tej definicji znacznika zdefiniowalibyśmy „id”, który będzie używany w IbatisReadDy.java do wykonywania zapytania Dynamic SQL SELECT na Baza danych.

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

Powyższa instrukcja SELECT działałaby na dwa sposoby -

  • Jeśli przekażesz identyfikator, zwraca rekordy odpowiadające temu identyfikatorowi. W przeciwnym razie zwraca wszystkie rekordy.

Plik IbatisReadDy.java

Ten plik zawiera logikę na poziomie aplikacji do odczytywania rekordów warunkowych z tabeli 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 ");
   }
}

Kompilacja i uruchomienie

Oto kroki, aby skompilować i uruchomić wyżej wymienione oprogramowanie. Upewnij się, że odpowiednio ustawiłeś PATH i CLASSPATH przed przystąpieniem do kompilacji i wykonania.

  • Utwórz plik Employee.xml, jak pokazano powyżej.
  • Utwórz plik Employee.java, jak pokazano powyżej, i skompiluj go.
  • Utwórz plik IbatisReadDy.java, jak pokazano powyżej, i skompiluj go.
  • Uruchom plik binarny IbatisReadDy, aby uruchomić program.

Otrzymasz następujący wynik, a rekord zostanie odczytany z tabeli EMPLOYEE.

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

Wypróbuj powyższy przykład, przechodząc nullas smc.queryForList ("Employee.findByID", null) .

Wyrażenia iBATIS OGNL

iBATIS zapewnia zaawansowane wyrażenia oparte na OGNL, które eliminują większość innych elementów.

  • if Instrukcja
  • wybierz, kiedy, w przeciwnym razie Oświadczenie
  • gdzie Oświadczenie
  • Instrukcja foreach

Instrukcja if

Najczęściej wykonywaną czynnością w dynamicznym SQL jest warunkowe dołączanie części klauzuli where. Na przykład -

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

Ta instrukcja zapewnia opcjonalny typ funkcji wyszukiwania tekstu. Jeśli nie podasz żadnego tytułu, wszystkie aktywne blogi zostaną zwrócone. Ale jeśli przekażesz tytuł, będzie szukał tytułu z podanymlike stan: schorzenie.

Możesz dołączyć wiele plików if warunki w następujący sposób -

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

Instrukcje dotyczące wyboru, kiedy i nie tylko

iBATIS oferuje chooseelement podobny do instrukcji switch w Javie. Pomaga wybrać tylko jeden przypadek spośród wielu opcji.

Poniższy przykład będzie wyszukiwał tylko według tytułu, jeśli zostanie podany, a następnie tylko według autora, jeśli zostanie podany. Jeśli żadne z nich nie zostanie podane, zwróci tylko polecane blogi -

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

Instrukcja Where

Spójrz na nasze poprzednie przykłady, aby zobaczyć, co się stanie, jeśli żaden z warunków nie zostanie spełniony. Otrzymasz SQL, który wygląda następująco -

SELECT * FROM BLOG
WHERE

To by się nie udało, ale iBATIS ma proste rozwiązanie z jedną prostą zmianą, wszystko działa dobrze -

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

Plik whereelement wstawia WHERE tylko wtedy, gdy zawierające znaczniki zwracają jakąkolwiek zawartość. Co więcej, jeśli ta treść zaczyna się od AND lub OR, wie, aby ją usunąć.

Instrukcja foreach

Element foreach umożliwia określenie kolekcji i zadeklarowanie zmiennych pozycji i indeksu, które mogą być używane w treści elementu.

Pozwala również określić ciągi otwierające i zamykające oraz dodać separator do umieszczenia między iteracjami. Możesz zbudowaćIN stan w następujący sposób -

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