Hibernate: Why is createAll(Batch Inserts) in Loop creating problem whereas create is executing fine?

120 views Asked by At

Parent Entity:

public class CustomerAgreement implements Serializable {
@OneToMany(mappedBy = "customerAgreement", orphanRemoval = true, fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST})
    private List<CustomerAgreementPeriod> agreementPeriods;

}

Child Entity

@Entity(name = "CustomerAgreementPeriod")
@Table(name = "CIM_SNOW_CUST_AGT_PERIODS_TAB")
public class CustomerAgreementPeriod  implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @SequenceGenerator(name = "CustomerAgreementPeriodSeq", sequenceName = "CIM_SNOW_CUST_AGT_PERIOD_SEQ")
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "CustomerAgreementPeriodSeq")
    @Column(name = "ID")
    private Long id;
    @ManyToOne
    @JoinColumn(name = "CUSTID")
    private CustomerAgreement customerAgreement;
    @Column(name = "PID")
    private String pid;
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "VALIDFROM")
    private Date validFrom;
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "VALIDTO")
    private Date validTo;

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public CustomerAgreement getCustomerAgreement() {
        return customerAgreement;
    }
    public void setCustomerAgreement(CustomerAgreement customerAgreement) {
        this.customerAgreement = customerAgreement;
    }
    public String getPid() {
        return pid;
    }
    public void setPid(String pid) {
        this.pid = pid;
    }
    public Date getValidFrom() {
        return validFrom;
    }
    public void setValidFrom(Date validFrom) {
        this.validFrom = validFrom;
    }
    public Date getValidTo() {
        return validTo;
    }
    public void setValidTo(Date validTo) {
        this.validTo = validTo;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((customerAgreement == null) ? 0 : customerAgreement.hashCode());
        result = prime * result + ((pid == null) ? 0 : pid.hashCode());
        result = prime * result + ((validFrom == null) ? 0 : validFrom.hashCode());
        result = prime * result + ((validTo == null) ? 0 : validTo.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        CustomerAgreementPeriod other = (CustomerAgreementPeriod) obj;
        if (customerAgreement == null) {
            if (other.customerAgreement != null)
                return false;
        } else if (!customerAgreement.equals(other.customerAgreement))
            return false;
        if (pid == null) {
            if (other.pid != null)
                return false;
        } else if (!pid.equals(other.pid))
            return false;
        if (validFrom == null) {
            if (other.validFrom != null)
                return false;
        } else if (!validFrom.equals(other.validFrom))
            return false;
        if (validTo == null) {
            if (other.validTo != null)
                return false;
        } else if (!validTo.equals(other.validTo))
            return false;
        return true;
    }


}

When i use following method in Dao and send batch of objects:

@Override
public void createAll(Collection<T> ts) {
    if (ts == null) {
        return;
    }
    for (T t : ts) {
        LOG.info(t.toString());
        em.persist(t);
    }
}

It gives following exception.

    2019-12-04 11:32:14,295 INFO  [stdout] (EJB default - 10) Hibernate: 
2019-12-04 11:32:14,295 INFO  [stdout] (EJB default - 10)     select
2019-12-04 11:32:14,295 INFO  [stdout] (EJB default - 10)         CUST_AGT_PERIOD_SEQ.nextval 
2019-12-04 11:32:14,295 INFO  [stdout] (EJB default - 10)     from
2019-12-04 11:32:14,295 INFO  [stdout] (EJB default - 10)         dual
2019-12-04 11:32:14,297 ERROR [org.jboss.as.ejb3.invocation] (EJB default - 10) WFLYEJB0034: EJB Invocation failed on component CustomerAgreementDaoImpl for method public abstract void com.evry.integrator.snow.model.dao.GenericDao.createAll(java.util.Collection): javax.ejb.EJBTransactionRolledbackException: A different object with the same identifier value was already associated with the session : [com.evry.integrator.snow.model.CustomerAgreementPeriod#-35]

When i create using following for single entity

@Override
public T create(final T t) {
    LOG.info(t.toString());
    this.em.persist(t);
    return t;
}

It runs fine.

List<CustomerAgreement> currentBatch = customerAgreement.subList(offset, Math.min(offset+itemsPerBatch, customerAgreement.size()));
customerAgreementDaoImpl.createAll(currentBatch);
customerAgreementDaoImpl.flush();

Could anyone assist how to do it in batch operation using createAll?

Also amazing thing is that with create it creates sequence with -33? enter image description here

1

There are 1 answers

0
fatherazrael On

This was fixed by setting property in persistance.xml

<property name="hibernate.id.new_generator_mappings" value="false" />       

and also changed GenerationStrategy from

 GenerationType.AUTO to GenerationType.Sequence

Not sure if this is good way to do this?