论坛首页 Java企业应用论坛

使用UserType来持久化复合类型属性

浏览 10070 次
该帖已经被评为精华帖
作者 正文
   发表时间: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

首先是一个业务对象:
import com.domainlanguage.time.TimeInterval;

public class RecordLog extends Entity {
    private String description;
    private TimeInterval interval;
    //getters and setters......
}


然后是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:
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);;
    }
}


偶们先来看看它是怎么运行的:
    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(););;
    }


怎么样, 是不是比原来的代码简单多了? 在背后干脏活,累活的就是这个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;
    }

}
   发表时间:2004-11-24  
不好意思,今天才看到。

   很好的UserType教材, 非常经典。 看了这文章后,我就明白了什么是UserType以及UserType如何定义和操作。

单这个问题本身,我认为用组件解决起来可能会更加简单,最多继承一下TimeInterval。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics