'InvalidDataAccessApiUsageException: detached entity passed to persist, while saving through JPA repository

I am trying to save the list of billing details that has many to one relation with batch details, However sometimes we are expected to have false billing data, so for that scenario we are logging in and saving the data through iteration. Below are the steps

  1. Saving all the billing info through the JPA saveAll method.
  2. By chance if we get DataIntegrityViolationException we need to process it individually by JPA save method

But for point 2 I am always getting InvalidDataAccessApiUsageException: detached entity passed to persist, exception for all the billing details. Can someone please help me identify and rectify the issue? I tried with multiple combinations of cascadeType.MERGE to either entity but neither worked.

Also is it possible for JPA savAll method to save the billing info which is valid and avoid an invalid ones? Like out of 10 objects if 2 are invalid, then it should save 8 objects in DB.

Below are entities

@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
@Table(name= "BLI_INFO")
public class BillingInfo implements Persistable<long> {
    @Id
    @Column(name = "BLI_ID")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "id_gen")
    @SequenceGenerator(sequenceName = "BLI_ID_SEQ", name = "id_gen", allocationSize = 1)
    private long billingId;

    ...
    // rest of the fields
    ...

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "BATCH_ID", nullable = false)
    private BatchInfo batchInfo;

   @Override
   public boolean isNew(){
      return true;
   }
}
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
@Table(name= "BATCH_INFO")
public class BatchInfo implements Persistable<long> {
    @Id
    @Column(name = "BATCH_ID")
    private String batchId;

    ...
    // rest of the fields
    ...

    @OneToMany(mappedBy = "batchInfo", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private List<BillingInfo> billingInfos;
}

below is the snippet of billing details that I am trying to save

@Autowired
BillingJpaRepository billingJpaRepository;

@Transactional
private void saveBillingRecords(List<BillingInfo> billingInfos) {
    try {
        billingJpaRepository.saveAll(billingInfos);
    } catch (DataIntegrityViolationException dataIntegrityViolationException) {
        this.saveBillingRecordsIndividually(billingInfos); // <------- 1. Occured due to data voilation 
    } catch (Exception ex) {
        throw ex;
    }
}

@Transactional
private void saveBillingRecordsIndividually(List<BillingInfo> billingInfos) {
    for(BillingInfo billingInfo : billingInfos) {
        try {
            billingJpaRepository.save(billingInfo);
        } catch (DataIntegrityViolationException dataIntegrityViolationException) {
            logger.error("data voilation exception occured");  // <------- 2. expectation to logged it here but
        } catch (Exception ex) {
            throw ex;   // <-------- 3. Actual exception (i.e. InvalidDataAccessApiUsageException) coming here
        }
    }
}

And below is the repository

@Repository
public interface BillingJpaRepository extends JpaRepository<BillingInfo, String> {
   // other jpql queries
}

======Solved======

While in my POJO I was implementing Persistable interface which always returning true value to the inNew method which tells hibernate to treat this entity as a new all the time which was causing the failure.

Used @PostLoad @PrePersist annotation to always update the state of the entity accordingly.

    @Transient
    private boolean isNew = false;

    @PrePersist
    @PostLoad
    void markNotNew() {
        this.isNew = false;
    }

    @Override
    public boolean isNew() {
        return isNew;
    }


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source