I createequals()
and hashCode()
methods in each Hibernate entity (if there is no inheritance) in my Java app. However, I am a little bit confused and wanted to be sure if I define properly. Could you pls clarify me about the following issues?
1. In IntelliJ, when I use "Genarate" feature (via Alt Insert), there are some templates like IntelliJ Default, Java 7 , etc. Which template should I use?
2. When using "Genarate" feature, which field should I include in my equals() and hashCode()
methods of the following entity?
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@Column(unique = true)
private String email;
// getter, setter, constructor...
}
3. Should I use annotation for simple and easy usage like @EqualsAndHashCode
? Or is it not flexible and should I prefer implementing explicitly?
CodePudding user response:
One rather crucial issue to consider is what a User
object represents.
It represents a row in the database
That means if the unid
is unset (i.e. you haven't save()
d it yet) then no 2 user objects can be identical to each other. After all, if you make 2 instances of User, set every value (other than id
which you don't mess with) to the same thing, and then save() both, you have 2 rows: Thus proving they aren't identical. However, to stick with java rules, they will be identical if there is reference identity (i.e. this == other
).
When unid
is set then the only thing that decides whether 2 User
objects are identical, is if their unid is identical. All other properties are irrelevant - after all, if you query the same DB for the same row (getting a separate User
instance for each, that have identical values), and then you setEmail
on one of them, then the email
field is no longer identical, but it doesn't matter: They refer to the same row, save one and the other changes along, thus, they are identical.
Conclusion: Write your own equals method that looks like:
if (other == null) return false;
if (other.getClass() != User.class) return false;
if (this == other) return true;
if (this.id == null || other.id == null) return false;
return this.id.equals(other.id);
And hashCode can just be id.hashCode()
, returning 0
or 31
if you prefer (or any other prime, won't make much of a difference in practice) if id
is null.
It represents a User
In that case, the fact that you can save()
them, and that they also have an id
representing absolutely nothing relevant about the user, just representing an 'implementation detail' of the backing storage system, you would compare everything except id
- Any 2 User object whose name and email are equal, are equal, even if the objects happen to represent 2 separate rows (somehow - you have a uniqueness constraint on email. But you can still make that happen - make a new instance that you haven't saved yet, the SQLException won't occur until you save it).
But those are each others exact opposite!
Yeah. They are. Annoying, isn't it? One checks only id
, the other checks everything except id
.
Hibernate/JPA is confused about what it thinks it wants, peddling itself as both a database abstraction (the first 'take') as well as an object persistence framework (which steers much closer to the second case), and thus I still haven't actually seen which of these 2 views is 'preferred' by hibernate.
Hence, uh.. pick one, I guess. I think the first one is far more 'correct' and far more likely to do what you want (keep in mind that hitting every property might cause quite the cascade in selects to fetch all those values, especially if you have interconnected stuff, i.e. references to other tables, that's one of a few reasons why the first view is 'better'), however, in my experience, it's less commonly deployed.
If you want to choose the second option, you can just use lombok's stuff. Make sure to mark id
with @EqualsAndHashCode.Exclude
. For the first - easier to just write it yourself, see snippet above.
CodePudding user response:
Use the option that generates fewer code and no need 3rd party libraries. I prefer Java7 . Include just the primary key field because the important thing is to verify if 2 differents instances are representing the same row in database.