Hibernate When is it necessary to implement equals and hashCode and if so how

De openkb
Aller à : Navigation, rechercher

Sommaire

Questions

http://stackoverflow.com/a/1431714/27358 http://stackoverflow.com/a/1431714/27358

Basically I want to avoid situations like the HashMap key problem in that link, or like the following:

    • Get a thing with a certain identity.
    • Modify it.
    • Add it to a set.
    • (later) Get another thing with the same identity.
    • Modify it.
    • Add it to the same set.
    • Fail to notice that this add doesn t actually happen, since the set thinks the thing is already there.
    • Do something with the things in the set.
    • Fail to notice that the change from step (5) is ignored, and we still have the state from step (2).

http://stackoverflow.com/questions/9089335/apart-from-immutable-value-objects-when-should-i-override-equals http://stackoverflow.com/questions/9089335/apart-from-immutable-value-objects-when-should-i-override-equals

Anyway, I m now in a Hibernate shop, and my more Hibernate-savvy colleagues are telling me this approach isn t going to work. Specifically, the claim seems to be that in the following scenario --

    • Hibernate loads a thing from the database -- we ll call it instance h1.
    • This thing is marshaled and sent somewhere via a web service.
    • The web service client fiddles with it and sends a modified version back.
    • The modified version is unmarshalled on the server -- we ll call it instance h4.
    • We want Hibernate to update the database with the modifications.

-- unless h1.equals(h4) (or perhaps h4.equals(h1), I m not clear, but I would hope it s transitive anyway so whatever), Hibernate will not be able to tell that these are the same thing, and Bad Things Will Happen.

So, what I want to know:

    • Is this true?
    • If so, why? What is Hibernate using equals() for?
    • If Hibernate needs h1 and h4 to be equal, how does it (and how do we) keep track of which one is the modified version?

http://stackoverflow.com/questions/1638723/equals-and-hashcode-in-hibernate http://stackoverflow.com/questions/1638723/equals-and-hashcode-in-hibernate

Answers

First of all, your original idea, that you should implement equals() and hashCode() only on immutable objects, certainly works, but it s stricter than it needs to be. You just need these two methods to rely on immutable fields. Any field whose value may change is unsuitable for use in those two methods, but the other fields need not be immutable.

Having said that, Hibernate knows they re the same object by comparing their primary keys. This leads many people to write those two methods to rely on the primary key. Hibernate docs recommend you don t do it this way, but many people ignore this advice without much trouble. It means you can t add entities to a Set until after they ve been persisted, which is a restriction that s not too hard to live with.

Hibernate docs recommend using a business key. But the business key should rely on fields that uniquely identify an object. The Hibernate docs say "use a business key that is a combination of unique, typically immutable, attributes." I use fields that have a unique constraint on them in the database. So, if your Sql CREATE TABLE statement specifies a constraint as

CONSTRAINT uc_order_num_item UNIQUE (order_num, order_item)

then those two fields can be your business key. That way, if you change one of them, both Hibernate and Java will treat the modified object as a different object. Of course, if you do change one of these "immutable" fields, you mess up any Set they belong to. So I guess you need to document clearly which fields comprise the business key, and write your application with the understanding that fields in the business key should never be changed for persisted objects. I can see why people ignore the advice and just use the primary key. But you could define the primary key like this:

CONSTRAINT pk_order_num_item PRIMARY KEY (order_num, order_item)

And you would still have the same problem.

Personally, I would like to see an annotation that specifies every field in the business key, and have an IDE inspection that checks if I modify it for persisted objects. Maybe that s asking too much.

Another approach, one that solves all of these problems, is to use a UUID for the primary key, which you generate on the client when you first construct an unpersisted entity. Since you never need to show it to the user, your code is not likely to change its value once you set it. This lets you write hashCode() and equals() methods that always work, and remain consistent with each other.

One more thing: If you want to avoid the problem of adding an object to a Set that already contains a different (modified) version of it, the only way is to always ask the set if it s already there before adding it. Then you can write code to handle that special case.

Source

License : cc by-sa 3.0

http://stackoverflow.com/questions/9089266/hibernate-when-is-it-necessary-to-implement-equals-and-hashcode-and-if-so

Related

Outils personnels
Espaces de noms

Variantes
Actions
Navigation
Outils