|
该帖已经被评为精华帖
|
|
|---|---|
| 作者 | 正文 |
|
最后更新时间:2005-09-07
在项目中常遇到用数字表示一种意思的字段,例如:type ,1 表示正常状态,2表示冻结状态,,,如果用HIBERNATE返回查询的结果集,只是把数据返回到页面是不行的,必须得对结果集进行过滤,把“1” 更替为 “正常状态后”,再返回,,如果用程序写,较麻烦,而且效率低,,得把结果集解开,更替,再封装,,,
不知道HIBERNATE有没有提供一种过滤更替的功能呢? 声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
|
| 返回顶楼 | |
|
最后更新时间:2005-09-07
这是一类典型的问题,即枚举类型的映射和表示。在Hibernate2.1版本中提供了enum的接口类型来处理这类问题,参考这个讨论:
http://forum.javaeye.com/viewtopic.php?t=8114&postdays=0&postorder=asc&highlight=enum&start=0 但是在Hibernate3中取消了enum类型的支持,Hibernate官方推荐使用UserType接口。不过使用UserType接口实际上会比较复杂,下面我将使用一个简单的案例来讲解使用UserType接口来解决这类问题的办法: User对象,是一个简单的域模型,User有一个UserTitle属性,可以是"雇员","经理","总监","CEO"等等,这是一个枚举属性,定义如下: package com.javaeye.simple.domain;
import java.io.Serializable;
public class UserTitle implements Serializable {
private int title;
public static final UserTitle EMPLOYEE = new UserTitle(0);
public static final UserTitle MANAGER = new UserTitle(1);
public static final UserTitle DIRECTOR = new UserTitle(2);
public static final UserTitle CEO = new UserTitle(3);
private UserTitle(int title) {
this.title = title;
}
public int toInt() {
return title;
}
public static UserTitle fromInt(int title) {
switch (title) {
case 0:
return EMPLOYEE;
case 1:
return MANAGER;
case 2:
return DIRECTOR;
case 3:
return CEO;
default:
throw new RuntimeException("Unknown Status");
}
}
public String toString() {
switch (title) {
case 0:
return "雇员";
case 1:
return "经理";
case 2:
return "总监";
case 3:
return "CEO";
default:
throw new RuntimeException("Unknown Status");
}
}
}
要说明的是,如果使用JDK5.0的enum,可以简化这个类的代码,此外真实的项目开发,不应该在代码中直接写中文,应该去读一个外部的配置文件,获得中文字符串的内容,这个地方大家可以自己去改。 |
|
| 返回顶楼 | |
|
最后更新时间:2005-09-07
User对象的代码:
/*
* Created on 2004-11-11
*
*/
package com.javaeye.simple.domain;
import java.util.Date;
/**
* @author Robbin Fan
*
*/
public class User {
private Long id;
private String username;
private String password;
private Date birthday;
private String gender;
private int age ;
private String department;
private String mail;
private UserTitle title;
public UserTitle getTitle() {
return title;
}
public void setTitle(UserTitle title) {
this.title = title;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getMail() {
return mail;
}
public void setMail(String mail) {
this.mail = mail;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
注意,我们需要一个UserTitleType的类,实现UserType接口,定义一个User对象的UserTitle属性是如何向数据库持久化的: package com.javaeye.simple.domain;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Types;
import java.sql.SQLException;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
public class UserTitleType implements UserType {
public int[] sqlTypes() {
int[] types = {Types.INTEGER};
return types;
}
public Class returnedClass() {
return UserTitle.class;
}
public boolean equals(Object x, Object y) throws HibernateException {
return x == y;
}
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
int title = rs.getInt(names[0]);
return rs.wasNull() ? null : UserTitle.fromInt(title);
}
public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
if (value == null) {
st.setNull(index, Types.INTEGER);
} else {
st.setInt(index, ((UserTitle) value).toInt());
}
}
public Object deepCopy(Object value) throws HibernateException {
return value;
}
public boolean isMutable() {
return false;
}
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) deepCopy(value);
}
public Object assemble(Serializable cached, Object owner) throws HibernateException {
return deepCopy(cached);
}
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return deepCopy(original);
}
}
注意nullSafeGet和nullSafeSet方法的代码,是如何实现UserTitle的字符串值和数据库中保存数字进行转换的。 最后是映射文件: <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.javaeye.simple.domain">
<class name="User">
<id name="id" unsaved-value="null">
<generator class="native"/>
</id>
<property name="username"/>
<property name="password"/>
<property name="gender"/>
<property name="age"/>
<property name="department"/>
<property name="mail"/>
<property name="birthday"/>
<property name="title" type="com.javaeye.simple.domain.UserTitleType">
</property>
</class>
</hibernate-mapping>
指明title属性是用户自定义的某类型。 |
|
| 返回顶楼 | |
|
最后更新时间:2005-09-07
在Java程序中指定user的title属性:
user.setTitle(UserTitle.MANAGER); session.save(user); 在页面输出: <% user.getTitle() %> 就可以打印出中文字符串表示。 |
|
| 返回顶楼 | |
|
最后更新时间:2005-09-07
这样在页面上显示不麻烦了,但保存时又得做转换了,总之还是麻烦。:wink:
user.setTitle(UserTitle.fromInt(Integer.parseInt(request.getParameter("userTitle")))); |
|
| 返回顶楼 | |
|
最后更新时间:2005-09-07
这个标题有点误导啊,初看还以为是session.filter的应用呢。
其实如果状态比较少,那么我个人认为还不如将问题推向前台,在前台进行逻辑处理,如果用JSTL,那么只要${type == 1 ? 'CEO' : '雇员'}。当然,如果状态比较多,可以考虑使用UserType。 事实上,写一个UserType所要关注的东西很多,其中的deepCopy,nullSafeGet和nullSafeSet等方法都要自己小心编写。robbin给出的应该只是一个简单的示例。 这种情况,你认为是在前台写一些类似<c:choose>或者各种逻辑判断的显示逻辑来得简单呢,还是在后台小心翼翼的写一个UserType方便呢?虽然在view层有逻辑有点bad smell |
|
| 返回顶楼 | |
|
最后更新时间:2005-09-07
我们通常在这种情况下,直接文件操作,或在数据库建look up table
robbin好文,受教不少。 不过,个人感觉确实是有点麻烦,如果有很多这样的域模型存在的情况下,那岂不是我要写大量相应的UserTitle和实现UserType接口的Type类。。。,那我还不如直接做个I/O交互算了,尽管要牺牲效率。 ps:或许是由于不习惯吧。 |
|
| 返回顶楼 | |
|
最后更新时间:2005-09-08
我一般用数组。数据库里存的是下标。存数据库也可以,也不是每次都要访问数据库,如果不是常常变得话,一次读入内存就够了。变了就把内存给刷一次。
|
|
| 返回顶楼 | |
|
最后更新时间:2005-09-08
downpour 写道 这个标题有点误导啊,初看还以为是session.filter的应用呢。
其实如果状态比较少,那么我个人认为还不如将问题推向前台,在前台进行逻辑处理,如果用JSTL,那么只要${type == 1 ? 'CEO' : '雇员'}。当然,如果状态比较多,可以考虑使用UserType。 事实上,写一个UserType所要关注的东西很多,其中的deepCopy,nullSafeGet和nullSafeSet等方法都要自己小心编写。robbin给出的应该只是一个简单的示例。 这种情况,你认为是在前台写一些类似<c:choose>或者各种逻辑判断的显示逻辑来得简单呢,还是在后台小心翼翼的写一个UserType方便呢?虽然在view层有逻辑有点bad smell 在页面处理并不好,一旦需要修改title的名称,你就满世界去改页面吧。 |
|
| 返回顶楼 | |
|
最后更新时间:2005-09-08
z_jordon 写道 这样在页面上显示不麻烦了,但保存时又得做转换了,总之还是麻烦。:wink:
user.setTitle(UserTitle.fromInt(Integer.parseInt(request.getParameter("userTitle")))); Integer.parseInt(request.getParameter("userTitle"))
这段代码是标准的从HTTPRequest里面取得参数值,和我的方案无关,即使不用我这种方案,你也是必须要写的。实际上我的方案仅仅是: user.setTitle(UserTitle.fromInt(title)); 和我上面举的例子一样 user.setTitle(UserTitle.MANAGER); 并没有增加任何复杂度。 |
|
| 返回顶楼 | |









