12月
21
2009
分類:
最近更新:
2009-12-21
Hibernate 查詢某個欄位的絕對值
當我們試圖從資料庫中查詢某個欄位的絕對值時,我們有兩種途徑。第一種是自定新的 Hibernate UserType ,再透過 HQL 查詢。
第二種則是利用 SQL abs()
函數,透過 SQL 查詢。
自定新的 Hibernate UserType 並不太難,僅需實作 UserType 介面,再套用一個範例來修改即可。 範例可參考 https://www.hibernate.org/388.html 。
Implements Hibernate's UserType to define a custom class for absolute integer.
package tw.idv.rock;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.Hibernate;
import org.hibernate.usertype.UserType;
/**
* Custom class for absolute values on the way out from the database, Hibernate 3 version.
* This is based on Paul Newport's work.
* @see https://www.hibernate.org/388.html
* @author rock
*/
public class AbsoluteInteger implements UserType {
public int[] sqlTypes() {
return new int[] { Types.INTEGER };
}
@SuppressWarnings("unchecked")
public Class returnedClass() {
return int.class;
}
public boolean equals(Object x, Object y) {
return (x == y) || (x != null && y != null && (x.equals(y)));
}
public Object nullSafeGet(ResultSet inResultSet, String[] names, Object o)
throws SQLException {
Integer val =
(Integer) Hibernate.INTEGER.nullSafeGet(inResultSet, names[0]);
return Math.abs(val);
}
public void nullSafeSet(
PreparedStatement inPreparedStatement,
Object o, int i)
throws SQLException {
Integer val = (Integer) o;
inPreparedStatement.setInt(i, val);
}
public Object deepCopy(Object o) {
if (o == null) {
return null;
}
return new Integer(((Integer) o));
}
public boolean isMutable() {
return false;
}
public Object assemble(Serializable cached, Object owner) {
return cached;
}
public Serializable disassemble(Object value) {
return (Serializable) value;
}
public Object replace(Object original, Object target, Object owner) {
return original;
}
public int hashCode(Object x) {
return x.hashCode();
}
}
Use this user type in Hibernate Mapping (HBM).
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="tw.idv.rock.model.MyMap" table="mymap">
<id name="id" type="int" unsaved-value="null">
<column name="id" sql-type="serial(10)" />
<generator class="sequence">
<param name="sequence">mymap_id_seq</param>
</generator>
</id>
<property name="length" type="tw.idv.rock.AbsoluteInteger"/>
<!--
<property name="length" type="int"/>
-->
</class>
</hibernate-mapping>
HQL Query
Query query = session.createQuery("from MyMap where length >= :length")
.setInteger("length", minLength);
items = query.list();
然而,透過 Hibernate 的 UserType 途徑取得欄位的絕對值之效能,遠遜於透過 SQL 的 abs()
函數。
SQLQuery query = session.createSQLQuery("select id, abs(length) as length "
+ " from " + MyMap.tableQuoteName() + " where length >= :length");
query.addEntity(MyMap.class);
query.setInteger("length", minLength);
items = query.list();
查詢結果集的內容愈多,則效能差異愈顯著。
如果你採用 SQL 方式取欄位的絕對值,則你不必定義新的 UserType 與 HBM。
樂多舊網址: http://blog.roodo.com/rocksaying/archives/11126093.html