Проблема с методом equals () в Hibernate - PullRequest
6 голосов
/ 29 августа 2011

Я разрабатываю приложение в 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
}

Существует ManyToOne двунаправленная связь между Employee и 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(), который не работает [поскольку он использует переменную-член для определения равенства, которое не было должным образом инициализировано].

Это кажется очень простой проблемой, но как мне ее решить? Или я проектирую свои уроки совершенно неправильно? Или мой метод equals должен быть переписан для сравнения других значений вместо ID, что, я думаю, было бы абсурдом.

Ответы [ 4 ]

6 голосов
/ 29 августа 2011

Это кажется очень простой проблемой, но как мне ее решить?Или я проектирую свои уроки совершенно неправильно?Или если мой метод equals будет переписан для сравнения других значений вместо ID, что, я думаю, было бы абсурдно.

Есть две разные философии относительно этого.

a) equals() / hashCode () на основе идентификатора БД

Недостаток: нельзя сравнивать постоянные и непостоянные объекты

b) equals () / hashCode () на основе содержимого

Недостаток: два объекта с одинаковым идентификатором могут оказаться не равными.

Я предпочитаю второй подход, он имеет больше смысла с точки зрения Java (хотя и не с точки зрения БДзрения). Единственное, что я хотел бы убедиться, это то, что вы никогда не смешиваете подходы.

Это обсуждалось много раз, кстати:

1 голос
/ 29 августа 2011

Перепишите ваш метод equals, чтобы он возвращал false, когда o равно нулю:

@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;
}
0 голосов
/ 29 августа 2011

Вы можете добавить временное поле с другим непостоянным идентификатором. (возможно, вам стоит перейти на "длинный" идентификатор). Примерно так на примере

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;
   }
 }

В любом случае вы должны убедиться, что не используется и не используется сохраненный сотрудник.

Другая стратегия - сначала сохранить сотрудника, а затем добавить его в отдел

.
0 голосов
/ 29 августа 2011

В спящем режиме обычно вы можете сказать ему использовать значение, если оно не было сохранено в БД. Например, я использовал -1 для идентификатора, который еще не был сохранен.

Вы должны инициализировать свои идентификаторы следующим образом, чтобы убедиться, что вы получаете согласованное поведение.

private int ID = -1;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...