ต่อจากตอนที่แล้วเราพบว่าทำไม mothod ใน DAO มันเยอะจังก็อย่าเพิ่งไปสนใจมากครับเพราะเพื่อความยืดหยุ่นเราจะสร้างมันไว้ก่อนนอกจากนี้ยังทะลึ่งมี พวกที่ลงท้าย
ด้วย Expression อีก method ที่ลงท้ายด้วย Expression นั้นจะเป็นพวกสร้าง Dynamic Query ทั้งหลายยกตัวอย่างเช่นผมต้องการสร้าง
SELECT * FROM USERS WHERE USERS.USR_ID LIKE '%username%'
แทนที่จะต้องไปสร้าง
<select> ... </select>
ใหม่เราก็สร้างเป็น dynamic block ก่อนหน้าตาเป็นแบบนี้
<sql id="Where_Clause" >
<iterate property="oredCriteria" conjunction="or" prepend="where" removeFirstPrepend="iterate" >
<isEqual property="oredCriteria[].valid" compareValue="true" >
(
<iterate prepend="and" property="oredCriteria[].criteriaWithoutValue" conjunction="and" >
$oredCriteria[].criteriaWithoutValue[]$
</iterate>
<iterate prepend="and" property="oredCriteria[].criteriaWithSingleValue" conjunction="and" >
$oredCriteria[].criteriaWithSingleValue[].condition$
#oredCriteria[].criteriaWithSingleValue[].value#
</iterate>
<iterate prepend="and" property="oredCriteria[].criteriaWithListValue" conjunction="and" >
$oredCriteria[].criteriaWithListValue[].condition$
<iterate property="oredCriteria[].criteriaWithListValue[].values" open="(" close=")" conjunction="," >
#oredCriteria[].criteriaWithListValue[].values[]#
</iterate>
</iterate>
<iterate prepend="and" property="oredCriteria[].criteriaWithBetweenValue" conjunction="and" >
$oredCriteria[].criteriaWithBetweenValue[].condition$
#oredCriteria[].criteriaWithBetweenValue[].values[0]# and
#oredCriteria[].criteriaWithBetweenValue[].values[1]#
</iterate>
)
</isEqual>
</iterate>
</sql>
จากนนั้นเราจะทำการไปสร้าง
<select> ... </select>
แบบ dynamic ขึ้นมาหน้าตาเป็นแบบนี้ครับ
<select id="Users_selectByExpression" resultMap="UsersResult" parameterClass="com.spring66.tutorial.model.UsersExpression" >
select USR_ID, USR_NAME, USR_PWD, USR_LEVEL, USR_FIRST_LOGIN, REG_DATE, LOG_DATE
from users
<isParameterPresent >
<include refid="Where_Clause" />
<isNotNull property="orderByClause" >
order by $orderByClause$
</isNotNull>
</isParameterPresent>
</select>
เพียงเท่านี้เราก็สามารถเขียน Dynamic SQL ได้จาก Java Code เลยครับยกตัวอย่างเช่น
UsersExpression usrEx = new UsersExpression();
usrEx.createCriteria().andUsrNameLike("%user%").andUsrIdEqualTo("1");
ได้เรื่อยๆครับซึ่งนี่เป็นหนึ่งในหลายๆวิธีที่เราสามารถสร้าง Dynamic SQL ได้โดยจุดนี้ถือเป็นจุดแข็งอีกเรื่องของ iBatis เพราะไม่ต้องปรับ skill มากแค่มีความรู้เรื่อง SQL ก็สามารถ
เดา code ได้เกือบทั้งหมดแล้วครับ โอเคต่อไปหลังจากสร้าง DAO แล้วอาการแดงเถือกจะหายไปต่อไปเราจะลอง เรียก test แล้วครับ และแน่นอนโดนด่าแน่นอนเพราะไม่มี bean ชื่อ
นี้ดังนั้น ให้ไวครับเขียน implementation คลาสของ interface ที่เราเพิ่งสร้างขึ้นมา
package com.spring66.tutorial.dao.ibatis;
import com.spring66.tutorial.dao.UsersDao;
import com.spring66.tutorial.model.Users;
import com.spring66.tutorial.model.UsersExpression;
import java.util.List;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
public class IbatisUsersDao extends SqlMapClientDaoSupport implements UsersDao {
public IbatisUsersDao() {
super();
}
public void insert(Users record) {
getSqlMapClientTemplate().insert("Users_insert", record);
}
public int updateByPrimaryKey(Users record) {
int rows = getSqlMapClientTemplate().update("Users_updateByPrimaryKey", record);
return rows;
}
public int updateByPrimaryKeySelective(Users record) {
int rows = getSqlMapClientTemplate().update("Users_updateByPrimaryKeySelective", record);
return rows;
}
public List selectByExpression(UsersExpression example) {
List list = getSqlMapClientTemplate().queryForList("Users_selectByExpression", example);
return list;
}
public Users selectByPrimaryKey(String usrId) {
Users key = new Users();
key.setUsrId(usrId);
Users record = (Users) getSqlMapClientTemplate().queryForObject("Users_selectByPrimaryKey", key);
return record;
}
public int deleteByExpression(UsersExpression example) {
int rows = getSqlMapClientTemplate().delete("Users_deleteByExpression", example);
return rows;
}
// some other methods
}
}
จะเห็นว่าคลาสนี้ extends มาจาก SqlMapClientDaoSupport แล้วเอ๊ะไอ้คลาสนี้มาจากไหนจริงๆแล้ว Spring เตรียมเครื่องมือที่ช่วยให้เราใช้ iBatis ได้สะดวกมากขึ้นไว้ให้แล้ว
ซึ่งการใช้ Template คลาสพวกนี้จะช่วยให้เราทำงานกับ ORM ต่างๆได้สะดวกมากขึ้นเพราะโดยปกติแล้วการใช้งาน ORM จะต้องมีการเขียน code ที่เป็น overhead เยอะพอสมควร
ดังนั้น สิ่งต่อไปที่เราต้องทำคือ ต้องสร้าง bean ใหม่ขึ้นมาหนึ่งตัวเพื่อใช้ระบุค่า configuration พื้นฐานต่างๆของ iBatis ดังนี้
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> <property name="configLocation" value="classpath:sqlmap-config.xml"/> <property name="dataSource" ref="dataSource"/> </bean>
พรอพเพอตี้ตัวแรก configLocation เป็นที่ที่เราใช้เก็บ sqlmap-config ซึ่งเป็นที่ระบุว่า mapping file ของเราอยู่ที่ใดและมีกี่ไฟล์ที่ถูกใช้งานอยู่
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> <property name="configLocation" value="classpath:sqlmap-config.xml"/> <property name="dataSource" ref="dataSource"/> </bean>
ของเรามีตารางเดียวครับ ดังนั้นเราก็จะระบุลงไปใน sqlmap-cinfig.xml ดังนี้
<sqlMapConfig> <sqlMap resource="ibatis/users.xml"/> </sqlMapConfig>
พรอพเพอตี้ตัวต่อไปคือ dataSource ก็คือเราจะต่อกับระบบฐานข้อมูลด้วย Connection ไหนต่อไปก็ทำการเพิ่ม Dao ของเราเข้าไปในระบบพร้อมทั้งระบุด้วยว่าเราจะขอใช้ sqlMapClient
<bean id="usersDao" class="com.spring66.tutorial.dao.ibatis.IbatisUsersDao"> <property name="sqlMapClient" ref="sqlMapClient"/> </bean>
จากตรงนี้เราจะเห็นได้ว่า ทุกครั้งที่เราต้องการเรียกใช้ sqlMapClient เราก็แค่เรียกมัน ไม่ต้องมานั้ง new ให้เมื่อยตุ้มครับ ถึงตรงนี้ทุกอย่างน่าจะครบแล้วก็ run test เลยครับ แน่นอน หล่อ
