Java 实体等于()、hashCode()和toString()。如何正确实施??
我正在使用bean中的所有可用字段实现实体的Java 实体等于()、hashCode()和toString()。如何正确实施??,java,hibernate,orm,entity,Java,Hibernate,Orm,Entity,我正在使用bean中的所有可用字段实现实体的equals()、hashCode()和toString() 当我尝试比较相等或打印obj状态时,前端出现了一些惰性init异常。这是因为实体中的某些列表可以延迟初始化 我想知道在实体对象上实现equals()和toString()的正确方法是什么。equals()和hashCode()应该使用一个-即一组唯一标识对象但不是其自动生成ID的属性来实现 在toString()中,您可以放置任何感兴趣的信息,例如所有字段 使用IDE(Eclipse、Net
equals()
、hashCode()
和toString()
当我尝试比较相等或打印obj状态时,前端出现了一些惰性init异常。这是因为实体中的某些列表可以延迟初始化
我想知道在实体对象上实现equals()
和toString()
的正确方法是什么。equals()
和hashCode()
应该使用一个-即一组唯一标识对象但不是其自动生成ID的属性来实现
在toString()
中,您可以放置任何感兴趣的信息,例如所有字段
使用IDE(Eclipse、NetBeans、IntelliJ)为您生成所有这些
为了避免
LazyInitializationException
,无论是在equals()
还是在您的视图(jsp)中,都可以使用。当您为Hibernate对象实现equals和hashCode方法时,重要的是
instanceof
编辑:关于不直接访问类属性的相同规则也适用于toString方法-仅使用getter可以保证返回类中真正包含的信息。除了其他人所说的以外,我还认为需要将Hibernate对象附加到会话以检索lazy信息。如果没有数据库连接,则无法加载这些列表:)我对toString()für Hibernate实体的实现如下:
@Override
public String toString() {
return String.format("%s(id=%d)", this.getClass().getSimpleName(), this.getId());
}
如有必要,my AbstractEntity(如上)的每个子类都会覆盖该方法:
@Override
public String toString() {
return String.format("%s(id=%d, name='%s', status=%s)",
this.getClass().getSimpleName(),
this.getId(),
this.getName(),
this.getStatus());
}
对于hashCode()和equals(),请记住Hibernate经常使用代理类。因此,我的equals()通常如下所示:
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
Class<AbstractEntity> c1 = Hibernate.getClass(this);
Class<AbstractEntity> c2 = Hibernate.getClass(obj);
if (!c1.equals(c2)) return false;
final AbstractEntity other = (AbstractEntity) obj;
if (this.getId() == null) {
if (other.getId() != null) return false;
}
else if (!this.getId().equals(other.getId())) return false;
return true;
}
@Entity
public class Book implements Identifiable<Long> {
@Id
@GeneratedValue
private Long id;
private String title;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Book)) return false;
Book book = (Book) o;
return getId() != null &&
Objects.equals(getId(), book.getId());
}
@Override
public int hashCode() {
return getClass().hashCode();
}
//Getters and setters omitted for brevity
}
@覆盖
公共布尔等于(对象obj){
如果(this==obj)返回true;
if(obj==null)返回false;
c1类=Hibernate.getClass(此类);
c2类=Hibernate.getClass(obj);
如果(!c1.等于(c2))返回false;
最终AbstractEntity other=(AbstractEntity)obj;
if(this.getId()==null){
if(other.getId()!=null)返回false;
}
else如果(!this.getId().equals(other.getId())返回false;
返回true;
}
正如其他人已经指出的那样。。。访问延迟加载的属性时要小心!如果一个简单的toString()甚至log.debug(实体)级联到几个延迟加载的对象和属性中,可能会导致大量的活动
public boolean equals(Object o) {
if(o == null)
return false;
Account account = (Account) o;
if(!(getId().equals(account.getId())))
return false;
return true;
}
但是当您有一个非持久化实体时会发生什么它将不工作,因为尚未分配其标识符
那么,让我们看看Java持久化与Hibernate的书中讨论了什么
业务密钥是一个属性或属性的某些组合,对于具有相同数据库标识的每个实例来说都是唯一的
所以
如果不使用代理主键,则会使用自然键
因此,假设您有一个用户实体,它的自然键是firstName和lastName(至少,他/她的firstName和lastName通常不会更改)。因此,它将作为
public boolean equals(Object o) {
if(o == null)
return false;
if(!(o instanceof User))
return false;
// Our natural key has not been filled
// So we must return false;
if(getFirstName() == null && getLastName() == null)
return false;
User user = (User) o;
if(!(getFirstName().equals(user.getFirstName())))
return false;
if(!(getLastName().equals(user.getLastName())))
return false;
return true;
}
// default implementation provided by NetBeans
public int hashcode() {
int hash = 3;
hash = 47 * hash + ((getFirstName() != null) ? getFirstName().hashcode() : 0)
hash = 47 * hash + ((getLastName() != null) ? getLastName().hashcode() : 0)
retrun hash;
}
很好用!我甚至使用模拟对象,如存储库、服务等
关于toString()方法,正如@Bozho所说,您可以放置任何有趣的信息。但是请记住一些web框架,例如Wicket和Vaadin,使用此方法来显示其值。我们在我们的超类中实现equals()和hashCode()。这项工作完美无瑕,尤其是在地图和列表等方面。
这必须是正确的,因为我们做了很多传递持久性
等于():
/**
*根据hibernate语义比较两个实体对象是否相等。这里我们假设
*新对象总是不同的,除非它们是相同的对象。如果从中加载对象
*数据库有一个有效的id,因此我们可以对照对象id进行检查。
*
*@see com.dolby.persist.bean.EntityObject#equals(java.lang.Object)
*/
@抑制警告(“未选中”)
@凌驾
公共最终布尔等于(最终对象){
如果(this==对象)返回true;
如果(object==null | | this.getClass()!=object.getClass())返回false;
最终的AbstractModelObject other=(AbstractModelObject)对象;
if(this.getId()==null | | other.getId()==null)返回false;
返回此.getId().equals(其他.getId());
}
hashCode():
/**
*返回enttiy对象哈希代码。
*
*我们在这里所做的是确保一旦使用了hashcode值,它就永远不会更改
*这个物体。这使我们能够对新对象使用对象标识,而不会遇到
*问题。
*
*
*事实上,这是一个问题的唯一情况是当我们保存一个新对象时,保持它在周围
*关闭会话后,在新会话中加载对象的新实例,然后
*比较一下。
*
*
*在这种情况下,我们得到A==B,但是A.hashcode!=b、 哈希码
*
*
*这将适用于所有其他场景,并且不会在
*对象的属性将被编辑。在中生成合成主键的要点
*首先是避免主键依赖于对象属性和
*因此,在对象的生命周期内可能会发生变化。
*
*
*@见
/**
* Returns an enttiy objects hashcode.
* <p>
* What we are doing here is ensuring that once a hashcode value is used, it never changes for
* this object. This allows us to use object identity for new objects and not run into the
* problems.
* </p>
* <p>
* In fact the only case where this is a problem is when we save a new object, keep it around
* after we close the session, load a new instance of the object in a new session and then
* compare them.
* </p>
* <p>
* in this case we get A==B but a.hashcode != b.hashcode
* </p>
* <p>
* This will work in all other scenarios and don't lead to broken implementations when the
* propety of the object are edited. The whole point in generating synthetic primary keys in the
* first place is to avoid having a primary key which is dependant on an object property and
* which therefore may change during the life time of the object.
* </p>
*
* @see java.lang.Object#hashCode()
*/
@Override
public final synchronized int hashCode() {
if (this.hashcodeValue == null) {
if (this.getId() == null) {
this.hashcodeValue = new Integer(super.hashCode());
}
else {
final int generateHashCode = this.generateHashCode(this.getId());
this.hashcodeValue = new Integer(generateHashCode);
}
}
return this.hashcodeValue.intValue();
}
public String toString() {
return "userId: " + this.userId + ", firstName: " + this.firstName + ", lastName: " + this.lastName + ", dir: " + this.dir + ", unit: " + this.unit + ", contractExpiryDate: " + this.contractExpiryDate + ", email: " + this.email + ", employeeNumber: " + this.employeeNumber + ", employeeType: " + this.employeeType + ", phone: " + this.phone + ", officeName: " + this.officeName + ", title: " + this.title + ", userType: " + this.userType;
}
public boolean equals(Object obj) {
[...]
return (toString().equals(other.toString()));
}
public int hashCode() {
return toString().hashCode();
}
@Entity
public class Book implements Identifiable<Long> {
@Id
@GeneratedValue
private Long id;
private String title;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Book)) return false;
Book book = (Book) o;
return getId() != null &&
Objects.equals(getId(), book.getId());
}
@Override
public int hashCode() {
return getClass().hashCode();
}
//Getters and setters omitted for brevity
}