Can a Kotlin data class equals() method be used wi

2019-08-01 08:04发布

问题:

Kotlin has a Data class that comes with toString(), equals(), hashCode(), and copy().

Can equals() and hashCode() be used "Straight out of the box" without further tuning for JPA classes? We usually have to spend a lot of time reading up on "Natural Keys", the persistence context lifecycle, etc. in articles linked below before feeling confident that we are doing the right thing:

  • Equals and Hashcode
  • the-jpa-hashcode-equals-dilemma

Can we simply rely on Kotlin's equals() and hashcode() implementations now?

回答1:

In my opinion, data classes in Kotlin should not be used unless you really understand what you are doing.

Overriding equals/hashCode on mutable data can cause a problem. Consider you have added instance of a mutable class to HashSet, then changed some if properties of that instance. This affects value returned by hashCode.

In turn, this makes it impossible for HashSet to find the instance, since it will look for it in completely different hashtable entry. You won't be able to remove this instance from HashSet!

Good examples of candidates to be data classes in kotlin are: complex numbers, constant-sized vectors. Bad examples are: JPA entities, DTOs.

As for JPA, these articles are opinionated. There's another opinion: you should not override equals and hashCode for JPA entities at all.

Rationale: JPA providers (Hibernate, EclipseLink) must guarantee that a === b iff a and b have the same primary key in table, and both a and b are in persistent state. This contract may be broken for detached entities. But, in my opinion working with detached entities is a bad practice that one should avoid. This only thing that may have sence is to store detached entities to merge them in another JPA transaction.



回答2:

JPA entities should depend on object identity, not on primary keys being equal - that's roughly 90% of what object-relational mapping is all about. Having a JPA implementation jump through all sorts of loops to create, maintain and propagate the Identity Map and then ignoring it might be a sign that you don't need JPA at all, and will cause problems. Especially if you are not 100% aware of what you are doing.

That said, probably you can use Kotlin data classes in many cases, provided that:

  • you don't store persistent objects in maps and sets
  • you keep the default constructor and don't try to touch object initialization in any way (providing default values etc)