I am trying to insert a list of entities which have one to one relation to another entity. It is possible that the one to one mapped object would be same for many parent entity. I am expecting that the same child entity is referred in foreign keys of parent, but actually duplicate rows are getting created. Here are my Entities.
@Builder @Entity public class PaymentInfoType1 { @Id Long id; LocalDate date; @Column(precision = 15, scale = 2) BigDecimal amount; String reference; @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "account", referencedColumnName = "id") Account account; } @Builder @Entity @EqualsAndHashCode(onlyExplicitlyIncluded = true) public class Account { @Id Long id; @EqualsAndHashCode.Include String name; @EqualsAndHashCode.Include String accountId; }
I am creating a list of PaymentInfoType1 based on the information received from a different system. Each PaymentInfoType1 get created along with its Account, which could have exactly the same info but different objects in realtime.
When i do:
PaymentInfoType1 first = // Created with some logic Account account1 = // name = sample & accountId = 123 first.setAccount(account1); PaymentInfoType1 second = // Created with some logic Account account2 = // name = sample & accountId = 123 second.setAccount(account2); // Both the above its own account object but the field have exactly same values. List<PaymentInfoType1> list = List.of(first, second); repo.saveAll(list);
I was expecting that there will be two rows in PaymentInfoType1 table and one in Account, but found that Account also has two rows. Looks like Equals and HashCode does not have any effect in this case.
How can handle this to not insert duplicate rows when the mapping objects are similar by equals/hashcode.
Advertisement
Answer
JPA does nothing with @EqualsAndHashcode
(that just generates class methods equals
and hashCode
).
JPA identifies entities by entity id annotated with @Id
(or @EmebeddedId
) and this id is also something that can be implemented and checked – and usually also generated (like some db sequence) – in the database level.
If you want to use Account
identified by name
and accountId
on JPA side you need to use @EmbeddedId
and @Embeddable
and get rid of @Id
. This would be something like:
@Embeddable public class AccountId { String name; String accountId; // maybe needs renaming... }
and then in the Account
:
@EmbeddedId AccountId accountId;
See this for example