浏览 5981 次
|
锁定老贴子 主题:使用UserType来持久化复合类型属性
该帖已经被评为精华帖
|
|
|---|---|
| 作者 | 正文 |
|
最后更新时间:2004-11-23
偶们经常会遇到一些用户需求, 需要实现一个区间类型的东东:
public class Entity { private Date startDate; private Date endDate; private ......; } 如项目的开始/结束时间, 人员的任职期间等等 但是如要比较这个对象和其他对象区间的关系, 就得写一些恶心的code: if(this.startDate > that.startDate && this.endDate < that.endDate) if(this.startDate < that.startDate) ...... 一堆的if else了. 或许你会觉得这些小东西这样写就可以了, 但是为了有一个更完美, 更好用的Domain Object, 是值得偶们在这些小细节上操劳的. 有一些现成的lib就是做这些东西的, 比如: http://timeandmoney.sourceforge.net/ http://joda-time.sourceforge.net/ 这里用timeandmoney lib为例子, 来介绍一下利用Hibernate的UserType来创建一个Domain Object 首先是一个业务对象: [code:1] import com.domainlanguage.time.TimeInterval; public class RecordLog extends Entity { private String description; private TimeInterval interval; //getters and setters...... } [/code:1] 然后是mapping文件:
<class name="RecordLog">
<id name="id">
<generator class="native"/>
</id>
<property name="description"/>
<property name="interval" type="TimeIntervalType">
<column name="LOWER_LIMIT"/>
<column name="INCLUDES_LOWER_LIMIT"/>
<column name="UPPER_LIMIT"/>
<column name="INCLUDES_UPPER_LIMIT"/>
</property>
</class>
一个操作它的Manager: [code:1] public class Manager extends HibernateDaoSupport { public RecordLog load(Long id) { return (RecordLog) getHibernateTemplate().load(RecordLog.class, id); } public void save(RecordLog log) { getHibernateTemplate().saveOrUpdate(log); } } [/code:1] 偶们先来看看它是怎么运行的: [code:1] public void test() { TimePoint nov01 = TimePoint.atMidnightGMT(2004, 11, 01); TimePoint nov03 = TimePoint.atMidnightGMT(2004, 11, 03); TimePoint nov02 = TimePoint.atMidnightGMT(2004, 11, 02); TimePoint nov05 = TimePoint.atMidnightGMT(2004, 11, 05); RecordLog log1 = new RecordLog(); log1.setDescription("Record Log 1"); log1.setInterval(TimeInterval.closed(nov01, nov03)); RecordLog log2 = new RecordLog(); log2.setDescription("Record Log 2"); log2.setInterval(TimeInterval.closed(nov02, nov05)); //这里, 偶们只取交叉区间 //比原来的一堆if else简洁多了吧? if(log1.getInterval().intersects(log2.getInterval())){ log1.setInterval(log1.getInterval().intersect(log2.getInterval())); } manager.save(log1); RecordLog loaded = manager.load(log1.getId()); assertEquals("Record Log 1", loaded.getDescription()); assertEquals(nov02, loaded.getInterval().lowerLimit()); assertEquals(nov03, loaded.getInterval().upperLimit()); assertTrue(loaded.getInterval().includesLowerLimit()); assertTrue(loaded.getInterval().includesUpperLimit()); } [/code:1] 怎么样, 是不是比原来的代码简单多了? 在背后干脏活,累活的就是这个TimeIntervalType和TimeAndMoney Lib: 代码格式好难看阿, 只好用quote 写道 public class TimeIntervalType implements UserType { private static final int[] SQL_TYPES = new int[] { Hibernate.TIMESTAMP.sqlType(), Hibernate.BOOLEAN.sqlType(), Hibernate.TIMESTAMP.sqlType(), Hibernate.BOOLEAN.sqlType() }; public int[] sqlTypes() { return SQL_TYPES; } public Class returnedClass() { return TimeInterval.class; } public boolean equals(Object x, Object y) throws HibernateException { if (x == y) return true; if (x == null || y == null) return false; return ((TimeInterval) x).compareTo((TimeInterval) y) == 0; } public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { TimePoint lower = TimePoint.from((Timestamp) Hibernate.TIMESTAMP.nullSafeGet(rs, names[0])); boolean lowerIncluded = ((Boolean) Hibernate.BOOLEAN.nullSafeGet(rs, names[1])).booleanValue(); TimePoint upper = TimePoint.from((Timestamp) Hibernate.TIMESTAMP.nullSafeGet(rs, names[2])); boolean upperIncluded = ((Boolean) Hibernate.BOOLEAN.nullSafeGet(rs, names[3])).booleanValue(); return new TimeInterval(lower, lowerIncluded, upper, upperIncluded); } public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { TimeInterval interval = (TimeInterval) value; Hibernate.TIMESTAMP.nullSafeSet(st, new Timestamp(((TimePoint) interval.lowerLimit()).asJavaUtilDate().getTime()), index); Hibernate.BOOLEAN.nullSafeSet(st, new Boolean(interval.includesLowerLimit()), index + 1); Hibernate.TIMESTAMP.nullSafeSet(st, new Timestamp(((TimePoint) interval.upperLimit()).asJavaUtilDate().getTime()), index + 2); Hibernate.BOOLEAN.nullSafeSet(st, new Boolean(interval.includesUpperLimit()), index + 3); } public Object deepCopy(Object value) throws HibernateException { if (value == null) return null; TimeInterval interval = (TimeInterval) value; return new TimeInterval((TimePoint) interval.lowerLimit(), interval.includesLowerLimit(), (TimePoint) interval.upperLimit(), interval .includesUpperLimit()); } public boolean isMutable() { return true; } } 声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
|
| 返回顶楼 | |
|
最后更新时间:2004-11-24
不好意思,今天才看到。
很好的UserType教材, 非常经典。 看了这文章后,我就明白了什么是UserType以及UserType如何定义和操作。 单这个问题本身,我认为用组件解决起来可能会更加简单,最多继承一下TimeInterval。 |
|
| 返回顶楼 | |





