Я хочу проверить, существует ли объект в члене Collection (@OneToMany
или @ManyToMany
) другого объекта:
if (entity2.getEntities1().contains(entity1)) { }
Я хочу проверить, существует ли объект в члене Collection (@OneToMany
или @ManyToMany
) другого объекта:
if (entity2.getEntities1().contains(entity1)) { }
Не обязательно. Существует три варианта:
не переопределить - таким образом, вы будете работать с экземплярами. Это хорошо в тех случаях, когда вы работаете с коллекциями только с сущностями, которые прикреплены к сеансу (и, следовательно, гарантированно являются одним и тем же экземпляром). Это (для меня) предпочтительный способ во многих случаях, потому что он требует меньше кода и меньше внимания при переопределении
переопределить hashCode()
и equals()
с помощью бизнес-ключа. Это может быть подмножество свойств, которые идентифицируют сущность. Например, для User
хорошим бизнес-ключом может быть username
или email
. Это считается хорошей практикой.
переопределить hashCode()
и equals()
только с использованием поля идентификатора. Это нормально в некоторых случаях, особенно если у вас есть назначенный вручную идентификатор (например, UUID). Это также прекрасно, если ваша организация никогда не войдет в коллекцию. Но для переходных объектов (без идентификатора), которые входят в коллекции, это вызывает проблемы, поэтому будьте осторожны с этой опцией. Как отметил seanizer, вам следует избегать этого. Как правило, всегда, если вы действительно не знаете, что делаете (и, возможно, документируете его)
Подробнее см. в этой статье. Также обратите внимание, что equals()
и hashCode()
привязаны и должны быть реализованы как с точно такими же полями.
Да, вы должны определить соответствующие методы equals()
и hashcode()
, но вы НИКОГДА не должны указывать идентификатор. (См. этот последний мой ответ в аналогичном вопросе)
Мы стремимся, чтобы 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()
.
Это единственный способ. Вы можете попробовать Pojomatic библиотеку, которая делает тяжелую работу для вас.
Да, вы должны!
Если вы не переопределите реализацию по умолчанию 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
}