Skip to content
Advertisement

Spring repository saveAll inserting duplicate rows for mapped entity

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

Advertisement