分享

Hibernate 实体对象的识别

 feimishiwo 2014-04-29
 
实体对象的识别:
   在基本的Java编程中,对象的识别也是一个必须要面对的问题,在Java中可以通过”==”运算符来判断两个对象是否具有相同的引用,还可以通过从根类Object继承而来的”equals()”方法,来判断两个对象的值是否相等。基于这两个Java提供的工具,我们可以轻松的判断两个对象的差别,但是在面对持久化逻辑时,这两个工具就遇到了它爱莫能助的新问题,比如我们现在有两个实体类,一个代表用户我们称为User,另一个代表用户的地址我们称为Address,并且UserAddress是一对多的关联关系。
我们看以下代码:
User user1=session.load(User.class,”1”);
user1.setAge(“27”);
User user2=session.load(User.class,”1”);
依照基本的Java编程规则user1user2无论是引用还是值都不相同,但是user1user2在数据库中确实是代表同一条记录,因此他们其实具备等价关系。怎样才能准确的确定实体对象的身份?站在数据库的角度,一条记录可以由主键来唯一确定,所以我们可以这样作出约定,只要两个实体的主键值相等,那么这两个实体对象就代表同一个实体对象。
  Hibernate而言,这个规则一样成立,在Hibernate中,net.sf.hibernate.engine.Key(在Hibernate3中是org.hibernate.engine.Key类)类封装了用于区别两个实体的信息。在这个类中,主要有三个信息,分别是实体对象的Class对象,实体类的名称,实体ID,通过ID Hibernate就可以将代表不同记录数据的实体对象区分开。另外Key类还有作为实体对象在缓存中标识的作用,Hibernate会根据Key在缓存中寻找是否有对应的实体对象。所以在实际开发中,当我们使用一些自动生成实体类的工具时,这些工具都会为我们自动生成,这个实体类的equals()方法和hashCode()方法,来实现上述规则,以便能够在实体对象比较时,自动区分不同的实体对象,比如User类会生成如下的equals()hashCode()方法:
public boolean equals(Object other){
 if(this==other) return true;
 if(!other instanceof User) return false;
 User castother=(User)other;
 return new EqualsBuilder().append(this.getId(),castother.getId()).isEquals();
}
public int hashCode(){
 return new HashCodeBuilder().append(getId()).toHashCode();
}
以上的代码实现了我们约定的逻辑,当两个实体主键相同时,我们就认为这两个实体表示的是两个相同的实体对象。
这种处理在通常情况下是不会出问题的,在我们平常的开发中也很少遇到问题,但是很少并不代表没有问题,我们来看下面的代码:
User user=(User)session.load(User.class,”1”);
Iterator it=user.getAddress().iterator();
Address addr=(Address)it.next();
 
User user2=(User)session2.load(User.class,”1”);
Iterator it2=user2.getAddress().iterator();
user2.getAddress().add(addr);
Transaction trans=session.beginTransaction();
session2.save(user2);
session.commit();
这段代码在执行时,会抛出NonUniqueObjectException异常,为什么会这样?这是因为,我们将从第一个Session中加载的Address对象,放入了由第二个Session所加载的同一个User对象的Set集合中,这时我们上述的规则将会失效,因为这个规则无法支持实体的跨Session识别。这种情况在实际开发中比较少见,但是作为合格开发人员,应该清楚这个情况的存在。如果在开发中真的出现这种情况时,该怎么办呢?这时我们就要通过值比对来覆盖equals()/hashCode()方法,所谓值比对就是就是将实体中所有的属性,挨个进行值比较和生成hash码,只要有一个属性不相同,我们就认为这两个实体是不同的两个实体。有时候值比对方法,还会用在有业务主键的时候,比如说如果两个User的名字相同,那么这两个实体就相同,这时属性Name就是业务主键,这时必须在User实体类的equals()方法实现对名字的值比较,并且针对Name生成Hash码。
注意:通常业务主键是由业务逻辑决定的。
 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多