Czy powinienem pisać metody equals () w encjach JPA?

Chcę sprawdzić, czy encja jest członkiem kolekcji (@OneToMany lub @ManyToMany) innej encji:

if (entity2.getEntities1().contains(entity1)) { }
Author: Sean Patrick Floyd, 2010-12-08

6 answers

Niekoniecznie. Istnieją trzy opcje:

  • Nie nadpisuj-w ten sposób będziesz pracować z instancjami. Jest to w porządku w przypadkach, gdy pracujesz z kolekcjami z tylko encjami, które są dołączone do sesji (a tym samym gwarantowane, że będą tą samą instancją). Jest to (dla mnie) preferowany sposób w wielu przypadkach, ponieważ wymaga mniej kodu i mniej uwagi przy nadpisywaniu

  • Zastąp hashCode() i equals() kluczem biznesowym. To może być podzbiór właściwości identyfikujących podmiot. Na przykład dla User dobrym kluczem biznesowym może być username lub email. Jest to uważane za dobrą praktykę.

  • Nadpisuje hashCode() i equals() używając tylko pola ID. W niektórych przypadkach jest to w porządku, szczególnie jeśli masz ręcznie przypisany identyfikator (np. UUID). Jest również w porządku, jeśli Twoja jednostka nigdy nie wejdzie do kolekcji. Ale w przypadku encji przejściowych (bez identyfikatora), które trafiają do kolekcji, powoduje to problemy, więc ostrożnie z tą opcją. Jak zauważył seanizer-należy tego unikać. Ogólnie rzecz biorąc, zawsze, chyba że jesteś naprawdę świadomy tego, co robisz (i być może dokumentujesz to)

Więcej szczegółów można znaleźć w tym artykule. Zauważ również, że equals()i hashCode() są powiązane i powinny być zaimplementowane z dokładnie tymi samymi polami.

 110
Author: Bozho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-06 15:58:13

Tak, powinieneś zdefiniować odpowiednie metody equals() i hashcode(), ale nigdy nie pozwól, aby id było częścią żadnej z nich. (Zobacz moją ostatnią odpowiedź w podobnym pytaniu)

 13
Author: Sean Patrick Floyd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:33:26
 7
Author: Cid54,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-12 18:10:27

Zazwyczaj pozwalamy IDE generować hashCode() i equals() dla nas. Bądź ostrożny. Podczas generowania tych metod dla encji JPA. Niektóre wersje equals() sprawdzania tożsamości klasy

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

Spowoduje to złamanie Twoich kolekcji z niektórymi bibliotekami JPA, ponieważ biblioteki te tworzą proxy do Twoich encji( podklas), jak na przykład MyGreatEntity_$$_javassist_7 w Hibernate.

In encje zawsze zezwalają na podklasy w equals().

 5
Author: zbig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-25 07:34:49

Tak, powinieneś!

Jeśli nie nadpisujesz domyślnego Java.lang.Object equals i hashCode realizacja:

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

    @Id
    @GeneratedValue
    private Long id;

    private String title;

    //Getters and setters omitted for brevity
}

Operacja merge zwróci inną instancję obiektu i umowa równości zostanie zerwana Jak wyjaśniono w tym poście .

Najlepszym sposobem jest użycie klucza biznesowego, takiego jak:

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

Możesz również użyć identyfikatora dla równości, ale pamiętaj, że implementacja hashCode powinna zawsze zwracać tę samą wartość, co wyjaśniono w tym samym post, o którym już wspomniałem:

@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
}
 5
Author: Vlad Mihalcea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-06 10:31:50

To jedyny sposób. Możesz spróbować Pojomatic library, która wykonuje ciężką pracę za Ciebie.

 2
Author: Boris Pavlović,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-08 14:11:13