Je souhaite vérifier si l'entité fait partie d'un membre de la collection (@OneToMany
ou @ManyToMany
) d'une autre entité:
if (entity2.getEntities1().contains(entity1)) { }
Pas nécessairement. Il y a trois options:
ne remplacez pas - vous travaillerez donc avec des instances. C'est très bien dans les cas où vous travaillez avec les collections avec uniquement des entités qui sont attachées à la session (et donc garanties d'être la même instance). C'est (pour moi) la voie préférée dans de nombreux cas, car elle nécessite moins de code et moins de considération lors de la substitution
remplacer hashCode()
et equals()
par une clé métier. Il peut s'agir d'un sous-ensemble de propriétés identifiant l'entité. Par exemple, pour un User
une bonne clé commerciale peut être le username
ou le email
. Ceci est considéré comme une bonne pratique.
remplacer hashCode()
et equals()
en utilisant uniquement le champ ID. C'est très bien dans certains cas, surtout si vous avez un identifiant attribué manuellement (comme un UUID). C'est également bien si votre entité n'entrera jamais dans une collection. Mais pour les entités transitoires (sans identifiant) qui entrent dans les collections, cela pose des problèmes, donc soyez prudent avec cette option. Comme l'a noté le seanizer - vous devriez l'éviter. Généralement, toujours, à moins que vous ne sachiez vraiment ce que vous faites (et peut-être que vous le documentiez)
Voir cet article pour plus de détails. Notez également que equals()
et hashCode()
sont liés et doivent être implémentés tous les deux avec exactement les mêmes champs.
Oui, vous devriez!
Si vous ne remplacez pas la valeur par défaut Java.lang.Object
equals
et hashCode
implémentation:
@Entity(name = "Book")
public class Book implements Identifiable<Long> {
@Id
@GeneratedValue
private Long id;
private String title;
//Getters and setters omitted for brevity
}
l'opération merge
renverra une instance d'objet différente et le contrat d'égalité sera rompu comme expliqué dans cet article .
La meilleure façon est d'utiliser une clé métier, comme ceci:
@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
}
Vous pouvez également utiliser l'identifiant pour l'égalité, mais sachez que l'implémentation de hashCode doit toujours renvoyer la même valeur que celle expliquée dans le même article que j'ai déjà mentionné:
@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
}
Oui, vous devez définir les méthodes equals()
et hashcode()
correspondantes, mais vous ne devez JAMAIS laisser l'id faire partie de l'une ou l'autre. (Voir ma réponse récente dans une question similaire)
Nous avons tendance à laisser IDE générer hashCode()
et equals()
pour nous. Attention cependant. Lorsque vous générez ces méthodes pour les entités JPA. Certaines versions de equals()
vérifie l'identité de la classe
// ... inside equals() - wrong approach for Entities (cause of generate proxies)
if (o == null || this.getClass() != o.getClass()) {
return false;
}
// ...
Cela casserait vos collections avec certaines bibliothèques JPA car ces bibliothèques créent des proxys pour vos entités (sous-classes), comme par exemple MyGreatEntity_$$_javassist_7
Dans Hibernate.
Dans les entités, autorisez toujours les sous-classes dans equals()
.