Hibernate中equals()方法的问题

时间:2011-08-29 14:52:31

标签: java hibernate

我正在Hibernate中开发一个应用程序,我有这样的模型类:

public class Employee
{
    private int ID;
    private String name;
    private Department department;
    //other properties
    //constructors, getters and setters
}

请注意,ID不是用户填充的值,而是使用GenerationType.Identity作为strategy填充。

我还有另一个班级Department如下:

public class Department
{
    private int ID;
    private String name;

    private Set<Employee> employees; //this is actually a HashSet

    //other implementations
}

ManyToOneEmployee之间存在Department双向关系。

所以要向现有的Employee添加新的Department,我会执行以下操作

Department existingDepartment = ...;
Employee newEmployee = ...;

existingDepartment.addEmployee(newEmployee);
employee.setDepartent(existinDepartment);

session.save(newEmployee);

现在从概念上讲,如果两个Employee对象具有相同的ID,则它们是相同的。因此,equals()类中的Employee方法如下所示:

public boolean equals(Object o)
{
    if(!(o instanceOf Employee))
    {
        return false;
    }

    Employee other = (Employee)o;

    if(this.ID == o.etID())
    {
        return true;
    }

    return false;
}

现在的问题是,当我创建new Employee();时,我没有ID,因为它会在持久化时分配。所以,当我说

existingDepartment.addEmployee(newEmployee);

HashSet对象的内部Department实际上正在使用被破坏的equals()方法[因为它使用成员变量来确定未正确初始化的相等]。 / p>

这似乎是一个非常基本的问题但是,我该如何解决?或者我设计的课程完全错了?或者我应该重新编写equals方法来比较其他值而不是ID,我认为这是荒谬的。

4 个答案:

答案 0 :(得分:6)

  

这似乎是一个非常基本的问题但是,我该如何解决?或者我   设计我的课完全错了?或者我的平等方法应该是   重写以比较其他值而不是ID,我想这会   是荒谬的。

对此有两种不同的理念。

a)基于DB id的equals()/ hashCode()

缺点:您无法比较持久对象和非持久对象

b)基于内容的equals()/ hashCode()

缺点:具有相同id的两个对象可能会变得不相等。

我更喜欢第二种方法,从Java的角度来看它更有意义(虽然不可能从数据库的角度来看)。 我唯一想确定的是你从不混淆方法。

之前已多次讨论过,顺便说一下:

  

答案 1 :(得分:1)

o为空时,重写你的equals方法,使其返回false:

@Override
public boolean equals(Object obj) {
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final Employee other = (Employee) obj;
    if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) {
        return false;
    }
    return true;
}

答案 2 :(得分:0)

在休眠中,通常可以告诉它在未保存到db时使用值。例如,我使用-1作为尚未存储的ID。

您应该像这样初始化您的ID,以确保您获得一致的行为。

private int ID = -1;

答案 3 :(得分:0)

您可以添加具有不同非持久性ID的瞬态字段。 (也许你应该升级到“长”id)。 例如

这样的东西
public class Employee {
  private static int lastTID = 0;
  private int ID = -1;
  private transient int tID;
 ..
 public Employee () {
    synchronized (getClass()) {
      tId = -- lastTID;
    }
 }
 public boolean equals(Object o) {
 ..
   Employee other = (Employee)o;
 ..
   if (ID != -1) {
    return ID == other.ID;
   } else {
    return other.ID == -1 && tID == other.tID;
   }
 }

在任何情况下,您都必须确保没有正在使用的已保存和未保存的员工。

另一个策略是首先保存Employee,然后将其添加到Department