Jak należy zaimplementować equals i hashcode podczas korzystania z JPA i Hibernate
Jak należy zaimplementować równe klasy modelu i hashcode w Hibernate? Jakie są typowe pułapki? Czy Domyślna implementacja jest wystarczająco dobra w większości przypadków? Czy jest sens używać kluczy biznesowych?
Wydaje mi się, że dość trudno jest poprawnie działać w każdej sytuacji, gdy bierze się pod uwagę leniwe pobieranie, generowanie id, proxy itp.
8 answers
Hibernate ma ładny i długi opis kiedy / jak nadpisać equals()
/ hashCode()
in documentation
Istotą tego jest to, że musisz się o to martwić, jeśli twoja istota będzie częścią Set
lub jeśli zamierzasz odłączać / dołączać jej instancje. Ten ostatni nie jest tak powszechny. Ten pierwszy jest zwykle najlepiej obsługiwany przez:
- bazowanie
equals()
/hashCode()
na kluczu biznesowym - np. unikalna kombinacja atrybutów, która nie zmieni się podczas obiektu (a przynajmniej sesji). - Jeśli powyższe jest niemożliwe, baza
equals()
/hashCode()
na głównym kluczu, jeśli jest ustawiony, a tożsamość obiektu /System.identityHashCode()
w przeciwnym razie. ważna część polega na tym, że musisz przeładować Twój Zestaw po dodaniu do niego i utrzymaniu nowego encji; w przeciwnym razie możesz skończyć z dziwnym zachowaniem (ostatecznie skutkującym błędami i / lub uszkodzeniem danych), ponieważ twój encja może zostać przypisana do wiadra nie pasującego do jego bieżącegohashCode()
.
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
2012-02-10 13:05:00
Nie sądzę, aby przyjęta odpowiedź była dokładna.
Aby odpowiedzieć na pierwotne pytanie:
Odpowiedź brzmi tak, w większości przypadków tak.Czy Domyślna implementacja jest wystarczająco dobra w większości przypadków?
Musisz tylko nadpisać equals()
i hashcode()
, jeśli encja będzie używana w Set
(co jest bardzo powszechne) i encja zostanie odłączona od sesji hibernacji, a następnie ponownie dołączona do niej (co jest rzadkim użyciem hibernate).
Zaakceptowana odpowiedź wskazuje, że metody muszą być nadpisane, jeślialbo warunek jest prawdziwy.
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
2012-10-29 03:38:23
Gdy encja jest ładowana przez leniwe ładowanie, nie jest instancją typu podstawowego, ale jest dynamicznie generowanym podtypem generowanym przez javassist, więc sprawdzenie tego samego typu klasy nie powiedzie się, więc nie używaj:
if (getClass() != that.getClass()) return false;
Zamiast:
if (!(otherObject instanceof Unit)) return false;
, co jest również dobrą praktyką, jak wyjaśniono na implementacja równości w praktykach Javy .
Z tego samego powodu dostęp do pól bezpośrednio może nie działać i zwracać null zamiast wartości bazowej, więc nie używaj porównanie właściwości, ale użyj getterów, ponieważ mogą one wyzwalać Ładowanie podstawowych wartości.
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
2013-01-10 10:21:15
The best equals
/hashCode
implementacja polega na użyciu unikalnego klucza biznesowego .
Klucz biznesowy powinien być spójny we wszystkich przejściach stanu podmiotu (transient, attached, detergent, removed), dlatego nie można polegać na ID dla równości.
Inną opcją jest przejście na identyfikatory uuid , przypisane przez logikę aplikacji. W ten sposób możesz użyć UUID do equals
/hashCode
ponieważ identyfikator jest przypisany przed otrzymaniem encji zaczerwienione.
Można nawet użyć identyfikatora encji dla equals
i hashCode
, ale wymaga to zawsze zwracania tej samej wartości hashCode
, aby upewnić się, że wartość hashCode encji jest spójna we wszystkich przejściach stanu encji. Sprawdź ten post, aby dowiedzieć się więcej na ten temat .
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-04 12:05:35
Tak, to trudne. W moim projekcie equals i hashCode opierają się na id obiektu. Problem tego rozwiązania polega na tym, że żadne z nich nie działa, jeśli obiekt nie został jeszcze utrzymany, ponieważ identyfikator jest generowany przez bazę danych. W moim przypadku jest to tolerowane, ponieważ w prawie wszystkich przypadkach przedmioty są trwale trwające od razu. Poza tym działa świetnie i jest łatwy do wdrożenia.
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
2009-10-28 17:19:24
Jeśli zdarzyło ci się zastąpić equals
, upewnij się, że spełniasz jego umowy: -
- symetria
- refleksyjne
- TRANSITIVE
- konsekwentny
- NON NULL
I nadpisać hashCode
, ponieważ jego umowa opiera się na equals
realizacji.
- element 9: zawsze nadpisuj hashCode, gdy nadpisujesz równe
Są poważne niezamierzone skutki, gdy nie przestrzegasz tych umów. Na przykład {[3] } może zwrócić błędną wartość boolean
jako że ogólny kontrakt nie jest spełniony.
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
2016-04-28 03:21:05
W dokumentacji Hibernate 5.2 jest napisane, że możesz nie chcieć implementować hashCode i w ogóle jest równy-w zależności od twojej sytuacji.
Ogólnie dwa obiekty załadowane z tej samej sesji będą równe, jeśli są równe w bazie danych (bez implementacji hashCode i equals).
To się komplikuje jeśli używasz dwóch lub więcej sesji. W tym przypadku równość dwóch obiektów zależy od implementacji metody equals.
Co więcej, będziesz miał kłopoty, jeśli twoja metoda equals porównuje identyfikatory, które są generowane tylko podczas utrzymywania obiektu po raz pierwszy. Może ich jeszcze nie być, gdy wezwani są równi.
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
2016-10-20 13:46:58
Jest tu bardzo ładny artykuł: https://docs.jboss.org/hibernate/stable/core.old/reference/en/html/persistent-classes-equalshashcode.html
Cytując ważny wiersz z artykułu:
Zalecamy implementację equals () i hashCode() przy użyciu klucza biznesowego równość. Równość klucza biznesowego oznacza, że metoda equals() porównuje tylko właściwości, które tworzą klucz biznesowy, klucz, który by zidentyfikować naszą instancję w realnym świecie (naturalnym kandydat klucz): {]}
W prostych słowach
public class Cat {
...
public boolean equals(Object other) {
//Basic test / class cast
return this.catId==other.catId;
}
public int hashCode() {
int result;
return 3*this.catId; //any primenumber
}
}
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
2016-01-02 12:50:47