我正在使用bean中的所有可用字段实现我的实体的equals()
,hashCode()
和toString()
。
当我尝试比较相等或者打印obj状态时,我在前端得到了一些Lazy init Exception。那是因为实体中的某些列表可以延迟初始化。
我想知道在实体对象上实现equals()
和toString()
的正确方法是什么。
答案 0 :(得分:17)
equals()
和hashCode()
应使用business key实现 - 即一组唯一标识对象的属性,但不是其自动生成的ID。
在toString()
中,您可以放置任何有趣的信息 - 例如所有字段。
使用您的IDE(Eclipse,NetBeans,IntelliJ)为您生成所有这些。
为了避免LazyInitializationException
,无论是在equals()
还是在您的视图(jsp)中,您都可以使用OpenSessionInView
。
答案 1 :(得分:10)
为Hibernate对象实现equals和hashCode方法时,
非常重要instanceof
代替更多信息:
Stackoverflow: overriding-equals-and-hashcode-in-java
Hibernate documentation: Equals and HashCode
编辑:关于不访问类属性的相同规则也直接应用于toString方法 - 仅使用getters保证返回实际包含在类中的信息。
答案 2 :(得分:7)
您可以依靠实体标识符来使用等于
来比较您的实体public boolean equals(Object o) {
if(o == null)
return false;
Account account = (Account) o;
if(!(getId().equals(account.getId())))
return false;
return true;
}
但是当你有一个非持久的实体时会发生什么。 无法使用,因为尚未分配其标识符。
让我们看看Java Persistence with Hibernate Book对它的讨论
业务键是属性或属性的某种组合,对于具有相同数据库标识的每个实例都是唯一的。
所以
如果您没有使用代理主键,则使用是自然键。
因此,假设您有一个用户实体,其自然键是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;
}
工作正常!我甚至使用Mock对象,如存储库,服务等
关于toString()方法,正如@Bozho所说,你可以把任何有趣的信息都放进去。但是请记住一些Web框架,比如Wicket和Vaadin,使用这种方法来显示它的值。
答案 3 :(得分:0)
除了其他人所说的,我还认为Hibernate对象仍需要附加到会话以检索惰性信息。如果没有数据库连接,则无法加载这些列表:)
答案 4 :(得分:0)
我对toString()fürHibernate实体的实现如下:
@Override
public String toString() {
return String.format("%s(id=%d)", this.getClass().getSimpleName(), this.getId());
}
如果需要,我的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;
}
正如其他人已经说过的那样......小心访问延迟加载的属性!如果级联到多个延迟加载的对象和属性中,简单的toString()或甚至log.debug(实体)可能会导致巨大的活动。
答案 5 :(得分:0)
我们在超类中实现了equals()和hashCode()。这项工作完美无瑕,特别是在地图和列表等方面。 这必须正确,因为我们做了很多传递性的持久性。
/**
* Compare two entity objects, following hibernate semantics for equality. Here we assume that
* new objects are always different unless they are the same object. If an object is loaded from
* the database it has a valid id and therefore we can check against object ids.
*
* @see com.dolby.persist.bean.EntityObject#equals(java.lang.Object)
*/
@SuppressWarnings("unchecked")
@Override
public final boolean equals(final Object object) {
if (this == object) return true;
if (object == null || this.getClass() != object.getClass()) return false;
final AbstractModelObject<ID> other = (AbstractModelObject<ID>) object;
if (this.getId() == null || other.getId() == null) return false;
return this.getId().equals(other.getId());
}
/**
* 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();
}
答案 6 :(得分:0)
这可能是最好和最直接的方法:
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();
}
答案 7 :(得分:0)
如果碰巧在Hibernate实体上覆盖了equals(),请确保履行合同: -
并覆盖hashCode
,因为其合同依赖于equals
实施。
Joshua Bloch(Collection框架的设计者)强烈遵循这条规则
如果不遵守合同,会产生严重的意外影响。例如,List.contains(Object o)
可能会返回错误的boolean
值,因为未达到一般合同。
答案 8 :(得分:0)
equals
/ hashCode
。Object
equals和hashCode实现,因为在merge
和实体之后这不起作用。您可以use the entity identifier as suggested in this post。唯一的问题是您需要使用始终返回相同值的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 31;
}
//Getters and setters omitted for brevity
}