Подтвердить что ты не робот

Должен ли я писать методы equals() в сущности JPA?

Я хочу проверить, существует ли объект в члене Collection (@OneToMany или @ManyToMany) другого объекта:

if (entity2.getEntities1().contains(entity1)) { }
4b9b3361

Ответ 1

Не обязательно. Существует три варианта:

  • не переопределить - таким образом, вы будете работать с экземплярами. Это хорошо в тех случаях, когда вы работаете с коллекциями только с сущностями, которые прикреплены к сеансу (и, следовательно, гарантированно являются одним и тем же экземпляром). Это (для меня) предпочтительный способ во многих случаях, потому что он требует меньше кода и меньше внимания при переопределении

  • переопределить hashCode() и equals() с помощью бизнес-ключа. Это может быть подмножество свойств, которые идентифицируют сущность. Например, для User хорошим бизнес-ключом может быть username или email. Это считается хорошей практикой.

  • переопределить hashCode() и equals() только с использованием поля идентификатора. Это нормально в некоторых случаях, особенно если у вас есть назначенный вручную идентификатор (например, UUID). Это также прекрасно, если ваша организация никогда не войдет в коллекцию. Но для переходных объектов (без идентификатора), которые входят в коллекции, это вызывает проблемы, поэтому будьте осторожны с этой опцией. Как отметил seanizer, вам следует избегать этого. Как правило, всегда, если вы действительно не знаете, что делаете (и, возможно, документируете его)

Подробнее см. в этой статье. Также обратите внимание, что equals() и hashCode() привязаны и должны быть реализованы как с точно такими же полями.

Ответ 2

Да, вы должны определить соответствующие методы equals() и hashcode(), но вы НИКОГДА не должны указывать идентификатор. (См. этот последний мой ответ в аналогичном вопросе)

Ответ 4

Мы стремимся, чтобы IDE генерировала для нас hashCode() и equals(). Будьте осторожны. Когда вы создаете эти методы для объектов JPA. В некоторых версиях equals() проверяется идентификатор класса

// ... inside equals() - wrong approach for Entities (cause of generate proxies)
if (o == null || this.getClass() != o.getClass()) {
        return false;
}
// ...

Это сломает ваши коллекции с некоторыми библиотеками JPA, поскольку эти библиотеки создают прокси-серверы для ваших сущностей (подклассов), например, например MyGreatEntity_$$_javassist_7 в Hibernate.

В объектах всегда допускаются подклассы в equals().

Ответ 5

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

Ответ 6

Да, вы должны!

Если вы не переопределите реализацию по умолчанию Java.lang.Object equals и hashCode:

@Entity(name = "Book")
public class Book implements Identifiable<Long> {

    @Id
    @GeneratedValue
    private Long id;

    private String title;

    //Getters and setters omitted for brevity
}

операция merge будет возвращать другой экземпляр объекта, а контракт равенства будет нарушен как объяснять в этом сообщении.

Лучший способ - использовать бизнес-ключ, например:

@Entity
public class Book implements Identifiable<Long> {

    @Id
    @GeneratedValue
    private Long id;

    private String title;

    @NaturalId
    private String isbn;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Book)) return false;
        Book book = (Book) o;
        return Objects.equals(getIsbn(), book.getIsbn());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getIsbn());
    }

    //Getters and setters omitted for brevity
}

Вы также можете использовать идентификатор для равенства, но помните, что реализация 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 Objects.equals(getId(), book.getId());
    }

    @Override
    public int hashCode() {
        return 31;
    }

    //Getters and setters omitted for brevity
}