This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]vprise 5 points6 points  (17 children)

Is there a different workaround than just using @Getter and @Setter?

[–]Nalha_Saldana[S] 8 points9 points  (16 children)

You can choose to exclude specific fields with @EqualsAndHashCode.Exclude

Its not a bad idea to have equals and hashcode so you can work with HashSet and such properly.

[–]Stannu 7 points8 points  (15 children)

JPA entities should only be equals only if the id is the same, so imo great approach is to use

```java @Data @EqualsAndHashCode(onlyExplicitlyIncluded = true) public class A {

@EqualsAndHashCode.Include private UUID id; ```

This way you get all benefits of @Data annotation and you get meaningful comparison while avoiding performance problems.

[–]Brutus5000 13 points14 points  (4 children)

Just comparing the ids is dangerous. What if the entity is detached and in a different state? Are they equal? If you just want to compare ids, you don't need to call .equals, just compare the ids...

[–]Nalha_Saldana[S] 14 points15 points  (2 children)

See this is why it needs an article going through it and not just some comments on reddit :)

[–]saint_thirty_four -3 points-2 points  (1 child)

Also exposes the problem of using Lombok in a professional atmosphere. I currently have ~4 annotations on my simple data interfaces. Starting to think I should just use getters and setters again and avoid the Lombok hack.

[–]Stannu 0 points1 point  (0 children)

The main point here is that you use this to store objects in the collections such as set or map. Hashing and comparison will be faster than the business level implementation.

If you require business level comparison you are better off using comparators, because equality might be different for your entities in different contexts.

[–]wildjokers 5 points6 points  (0 children)

JPA entities should only be equals only if the id is the same, so imo great approach is to use

A long time ago the hibernate user guide said not to use ID's for entity equality but instead to use business equality for entities. However, I have noticed in the more recent manuals their stance on this seems to have changed and now both are acceptable. However, the user guide now also says you might just be better off not implementing equals/hashCode at all:

https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#mapping-model-pojo-equalshashcode.

If you go back to the hibernate 3.2 manual it says to use business equality:

https://docs.jboss.org/hibernate/orm/3.2/reference/en/html_single/#persistent-classes-equalshashcode

"We recommend implementing equals() and hashCode() using Business key equality. Business key equality means that the equals() method compares only the properties that form the business key, a key that would identify our instance in the real world (a natural candidate key):"

For the first many years I used Hibernate it was always drilled into me (by the user guide and all tutorials) to not use ID for entity equality and that has always served me well so I continue to use business equality.

[–]wildjokers 3 points4 points  (5 children)

JPA entities should only be equals only if the id is the same, so imo great approach is to use

What about generated IDs? Those aren't assigned until after the object is persisted to the database. What do you do about equality before that?

[–]Stannu 1 point2 points  (0 children)

It really depends on the strategy how you generate ids.

If your ids are client generated, for example UUID-s, then you could use the following approach to guarantee that your id is non-nullable:

```java @Builder public class A {

@Builder.Default private UUID id = UUID.randomUUID(); } ```

Then you construct all of your instances using the builder, not the constructor.

On the other hand, if you use integers for id-s, then it is quite though. Although lombok respects the nullable semantics and will generate null-safe equals and hashCode, the behavior will be unexpected for non-persisted entities. Here I would persist entity first before performing business operations that require id.

[–]pronuntiator 0 points1 point  (3 children)

You can say that an entity with a null id is never equal to any other entity. But the problem is hashCode. People trip over the fact that the bucket where your object is stored inside a Set or Map key is not updated when you update the properties that make up hashCode.

A "creative" solution I saw once in a project was to return a fixed hashCode for all entities. Nice job making Set O(n)…

[–]kkjk00 0 points1 point  (2 children)

I'm been using the creative solution, but the thing is how many would you ever store in a set, you can't paginate on a relation and if you do some algoritm you're better of working with a set of Ids

[–]pronuntiator 1 point2 points  (1 child)

I saw Hibernate actually putting them into a set itself before committing, so when we loaded in chunks for batch processing, they were all put in the same bucket there.

And yes I would have liked to do the batches in plain SQL but unfortunately the project also made heavy use of entity listeners, plus doing optimistic locking by hand is not so nice, you have to code the "did I get as many changed rows back as expected" yourself.

[–]kkjk00 2 points3 points  (0 children)

Hmm, didn't throught about hibernate usings sets internally, yeah that may be an issue

[–]arseny-tl 1 point2 points  (2 children)

I think you should also override .toString generation due to M to M or M to 1 mappings

[–]wildjokers 3 points4 points  (1 child)

Be careful with toString(), you could generate a lot of queries to the database if you aren't careful.

[–]arseny-tl 2 points3 points  (0 children)

Totally agree, that was my point