The NoteBook of EricKong

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  611 Posts :: 1 Stories :: 190 Comments :: 0 Trackbacks

#

假设有一个实体类,用于存放用户信息,其定义如下:

package events;
import java.util.*;
public class Person {
    private Long id;
    private int age;
    private String firstname;
    private String lastname;
    public Person() {}

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getFirstname() {
        return firstname;
    }
    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }
    public String getLastname() {
        return lastname;
    }
    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    private Set emailAddresses = new HashSet();
    public Set getEmailAddresses() {
        return emailAddresses;
    }
    public void setEmailAddresses(Set emailAddresses) {
        this.emailAddresses = emailAddresses;
    }

    private Set events = new HashSet();
    // Defensive, convenience methods
    protected Set getEvents() {
        return events;
    }
    protected void setEvents(Set events) {
        this.events = events;
    }
    public void addToEvent(Event event) {
        this.getEvents().add(event);
        event.getParticipants().add(this);
    }
    public void removeFromEvent(Event event) {
        this.getEvents().remove(event);
        event.getParticipants().remove(this);
    }
}

 
则相应的描述POJO--->Person.hbm.xml中的配置信息如下:

<?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>
    <class name="events.Person" table="PERSON">
        <id name="id" column="PERSON_ID">
            <generator class="identity" />
        </id>
        <property name="age" />
        <property name="firstname" />
        <property name="lastname" />
        <set name="events" table="PERSON_EVENT">
            <key column="PERSON_ID" />
            <many-to-many column="EVENT_ID" class="events.Event" />
        </set>
        <set name="emailAddresses" table="PERSON_EMAIL_ADDR">
            <key column="PERSON_ID" />
            <element type="string" column="EMAIL_ADDR" />
        </set>
    </class>
</hibernate-mapping>


说明:
1.class 节点

name: 类名

table: 类对应表名,默认为类名称

dynamic-update: 生成更新字段时,只包含发生变动的字段,默认为false。

dynamic-insert: 生成insert语句时仅包含非null字段

Proxy: 代理类,默认为空

discriminator-value: 子类辨别标识用于多态支持

where: 通过限定条件查询结果集。如:查询有籍在校学生的信息可以使用"where studentstatus='0'"

2.id节点

1.column               字段名称
2.type                 字段类型
3.length               字段长度
4.unsaved-value        用于判断对象值是否已经保存
5.generator-class      主键产生方式
                       assigned
                       hilo
                       seqhilo
                       increment
                       identity
                       sequence
                       native
                       uuid.hex
                       uuid.string
                       foreign



3.property 节点

1.column               数据库表字段名称
2.type                 类型
3.length               长度
4.not-null             字段是否允许为空
5.unique               字段是否允许唯一(是否允许重复值)
6.insert               insert操作时,是否允许包含本字段数值
7.update               update操作时,是否包含本字段数据





Event.hbm.xml

<?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>
 <class name="events.Event" table="EVENTS">
  <id name="id" column="EVENT_ID">
   <generator class="native" />
  </id>
  <property name="date" type="timestamp" column="EVENT_DATE" />
  <property name="title" />
  <set name="participants" table="PERSON_EVENT" inverse="true">
   <key column="EVENT_ID" />
   <many-to-many column="PERSON_ID" class="events.Person" />
  </set>
 </class>
</hibernate-mapping>
posted @ 2010-05-11 14:06 Eric_jiang 阅读(800) | 评论 (0)编辑 收藏

  Hibernate提供客户化映射类型接口,使用户能以编程方式创建自定义的映射类型来将持久化类任意类型的属性映射到数据库中。使用客户化映射类型,需要实现org.hibernate.usertype.UserType接口。这是个强大的功能,也是Hibernate的最佳实践之一。我们经常提到ORM中很困难的一点便是O的属性和R的属性不能一一映射,而Hibernate提供的UserType无疑给出了一个很好的解决方案。本文给出使用客户化映射类型的两个例子,算是对Hibernate初学者的抛砖。
    第一个例子是使用UserType映射枚举类型。假设Account表中含有一sex列,类型为tinyint(当前其0代表男,1代表女,将来可能出现2等代表其他性别类型);我们当然可以在对应的Account类中添加int类型的sex属性,但这种数字化无显示意义且类型不安全的枚举不是很好的解决方式,这里就采用了java5的enum来作为Account类的性别属性(如果不熟悉java5的enum,也可采用《effective java》中提到的经典的类型安全的枚举方案)。在Account添加enum Gender:

public class Account extends AbstractDomain<Long>{
    
    
public enum Gender{
        Male(
"male",0),
        Female(
"female",1);
        
        
private String name;
        
private int value;
        
        
public String getName() {
            
return name;
        }
        
public int getValue() {
            
return value;
        }
        
        
private Gender(String name,int value){
            
this.name = name;
            
this.value = value;
        }
        
        
public static Gender getGender(int value){
            
if(0 == value)return Male;
            
else if(1 == value)return Female;
            
else throw new RuntimeException();
        }
        
    }
    
    
private Gender gender;
    
public Gender getGender() {
        
return gender;
    }
    
public void setGender(Gender gender) {
        
this.gender = gender;
    }
       
//省略其他    
}

    接下来定义实现UserType接口的GenderUserType:

public class GenderUserType implements UserType{

    
public Object assemble(Serializable arg0, Object arg1) throws HibernateException {
        
return null;
    }

    
/*
     *  这是用于Hibernate缓存生成的快照,由于Gender是不可变的,直接返回就好了。
     
*/
    
public Object deepCopy(Object arg0) throws HibernateException {
        
return arg0;
    }

    
public Serializable disassemble(Object arg0) throws HibernateException {
        
return null;
    }

    
/*
     * 由于Gender是不可变的,因此直接==了,这个方法将在insert、update时用到。
     
*/
    
public boolean equals(Object x, Object y) throws HibernateException {
        
return x == y;
    }

    
public int hashCode(Object o) throws HibernateException {
        
return o.hashCode();
    }

    
/*
     * 表明Gender是不是可变类(很重要的概念哦),这里的Gender由于是枚举所以是不可变的
     
*/
    
public boolean isMutable() {
        
return false;
    }

    
/*
     *  从ResultSet读取sex并返回Gender实例,这个方法是在从数据库查询数据时用到。
     
*/
    
public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
        
int value = rs.getInt(names[0]);
        
return Account.Gender.getGender(value);
    }

    
/*
     *  将Gender的value设置到PreparedStatement。
     
*/
    
public void nullSafeSet(PreparedStatement ps, Object value, int index) throws HibernateException, SQLException {
        if(value == null){
            ps.setInt(index,Account.Gender.Male.getValue());
        }else{
            ps.setInt(index,((Account.Gender)value).getValue());
        }

    }

    
public Object replace(Object arg0, Object arg1, Object arg2) throws HibernateException {
        
return null;
    }

    
/*
     * 设置映射的Gender类
     
*/
    
public Class returnedClass() {
        
return Account.Gender.class;
    }

    
/*
     *  设置Gender枚举中的value属性对应的Account表中的sex列的SQL类型
     
*/
    
public int[] sqlTypes() {
        
int[] typeList = {Types.TINYINT};
        
return typeList;
    }
}

    最后在Account的配置文件中配置gender属性就好了:
<property name="gender" type="org.prague.domain.util.GenderUserType" column="sex"></property>
    除了可以使用 UserType映射枚举类型,也可以使用Hibernate的PersistentEnum来实现同样的功能,感兴趣的朋友可以参考文章http://www.hibernate.org/203.html。

    
    第二个例子是关于email的。假设Account表中email是一个varchar型的字段,而Account中的Email是如下的类:

public class Email {
    String username;

    String domain;

    
public Email() {
    }

    
public Email(String username, String domain) {
        
this.username = username;
        
this.domain = domain;
    }

    
public String getUsername() {
        
return username;
    }

    
public String getDomain() {
        
return domain;
    }

    
    
public void setDomain(String domain) {
        
this.domain = domain;
    }

    
public void setUsername(String username) {
        
this.username = username;
    }

    
public String toString() {
        
return username + '@' + domain;
    }

    
public static Email parse(String email) {
        Email e 
= new Email();
        
int at = email.indexOf('@');
        
if (at == -1) {
            
throw new IllegalArgumentException("Invalid email address");
        }

        e.username 
= email.substring(0, at);
        e.domain 
= email.substring(at + 1);

        
return e;
    }

    @Override
    
public int hashCode() {
        
final int PRIME = 31;
        
int result = 1;
        result 
= PRIME * result + ((domain == null? 0 : domain.hashCode());
        result 
= PRIME * result + ((username == null? 0 : username.hashCode());
        
return result;
    }

    @Override
    
public boolean equals(Object obj) {
        
if (this == obj)    return true;
      
if(null == obj)return false;
        
if (getClass() != obj.getClass())
            
return false;
        
final Email other = (Email) obj;
        
if (domain == null) {
            
if (other.domain != null)
                
return false;
        } 
else if (!domain.equals(other.domain))
            
return false;
        
if (username == null) {
            
if (other.username != null)
                
return false;
        } 
else if (!username.equals(other.username))
            
return false;
        
return true;
    }
}
    email是Account类的一个属性:
public class Account extends AbstractDomain<Long>{
    
    
private Email email;
    
public Email getEmail() {
        
return email;
    }
    
public void setEmail(Email email) {
        
this.email = email;
    }

    
//省略其他    
}

    这样的情况下,需要将email的username + '@' + domain映射到Account表的email列,定义一个EmailUserType如下:
 
   public class EmailUserType implements UserType{

    
public Object assemble(Serializable arg0, Object arg1) throws HibernateException {
        
return null;
    }

    
public Object deepCopy(Object o) throws HibernateException {
        
if(null == o)return null;
        Email e 
= (Email)o;
        
return new Email(e.getUsername(),e.getDomain());
    }

    
public Serializable disassemble(Object arg0) throws HibernateException {
        
return null;
    }

    
public boolean equals(Object x, Object y) throws HibernateException {
        
if(x == y)return true;
        
if(x == null || y == null)return false;
        
boolean  f = x.equals(y);
        
return f;
    }

    
public int hashCode(Object o) throws HibernateException {
        
return o.hashCode();
    }

    
public boolean isMutable() {
        
return true;
    }

    
public Object nullSafeGet(ResultSet rs, String[] names, Object o) throws HibernateException, SQLException {
        String email 
= rs.getString(names[0]);
        
if(email == null)return null;
        
int index = email.indexOf("@");
        
if(index < 0)throw new RuntimeException();
        
return new Email(email.substring(0,index),email.substring(index+1));
    }

    
public void nullSafeSet(PreparedStatement ps, Object o, int index) throws HibernateException, SQLException {
        
if(o == null )ps.setNull(index, Types.VARCHAR);
        
else{
            Email e 
= (Email)o;
            
if(e.getDomain() == null || e.getUsername() == null)ps.setNull(index, Types.VARCHAR);
            
else{
                String email 
= e.getUsername() + "@" + e.getDomain();
                ps.setString(index, email);
            }
        }
        
    }

    
public Object replace(Object arg0, Object arg1, Object arg2) throws HibernateException {
        
return null;
    }

    
public Class returnedClass() {
        
return Email.class;
    }

    
public int[] sqlTypes() {
        
int[] typeList = {Types.VARCHAR};
        
return typeList;
    }
}

    最后配置下 email 属性:
<property name="email" type="org.prague.domain.util.EmailUserType" column="email"></property>
    相比于Gedner,Email是一个可变类(如果想将其变为不可变类,只需要去掉属性的set方法),因此EmailUserType中的equals要用到Email的equals(hashCode())方法,而deepCopy(Object o) 要做到是深拷贝,否则即便Email属性内容改变,由于Hibernate缓存中的快照指向的对象不变,在update时可能不起作用(在指定了dynamic-update属性的清况下)。
posted @ 2010-05-11 11:40 Eric_jiang 阅读(381) | 评论 (0)编辑 收藏

仅列出标题
共57页: First 上一页 49 50 51 52 53 54 55 56 57