EntityListener onAfterUpdate working twice

I want to insert records from first entity to a second entity when a value of specific field of the first entity changed. For this I am trying use onAfterUpdate Listener of Entity 1 but the records are inserted twice.

Here is the listener:


  @Override
    public void onAfterUpdate(JournalHeader entity) {
        if (entity.getPosted() == true) {
            postEntries(entity);
        }
    }

    //@Override
    @Transactional
    public void postEntries(JournalHeader entity) {

        try (Transaction tx = persistence.createTransaction()) {
            TypedQuery<JournalDetail> detailQuery = persistence.getEntityManager().createQuery("select e from mydb$JournalDetail e " +
                    "where e.glJournalHeader.id = ?1 ", JournalDetail.class); //and c.workShift.id = ?2 and c.capacityUnit=?3     glJournalHeader.id
            detailQuery.setParameter(1, entity.getId());

            List<JournalDetail> details = detailQuery.getResultList();

            for (JournalDetail detail : details) {
                GlAccountsBalance balance = metadata.create(GlAccountsBalance.class);
                balance.setCompany(entity.getCompany());
                balance.setFinancialPeriod(entity.getPeriod());
                balance.setFinancialYear(entity.getFinaYear());
                balance.setGlAccounts(detail.getGlAccounts());
                balance.setGlAccountsSub(detail.getGlAccountsSub());
                balance.setCredit(detail.getCredit());
                balance.setDebit(detail.getDebit());
                persistence.getEntityManager().persist(balance);
            }
            tx.commit();
        }
    }

Thanks for helping where I am making the mistake.

Hi Mortoza,
I don’t know why you have duplicates, perhaps your detailQuery returns more results than you expected.
But I would suggest using BeforeUpdateEntityListener and do everything in a single transaction.
See for example cuba platform - Create Entity by using EntityListener - Stack Overflow

Hi Konstantin
Just tried using the BeforeUpdateEntityListener, same double records!!

the the detail entity has 2 records with reference to the header entity selected. I am expecting those two records to be inserted to the 2nd table but it is inserting 4 records.

  1. Clean your BeforeUpdate listener from transaction management code, and check again. If the problem persists, provide the source code of your entities and the listener.
  2. Ensure that your listener is invoked twice. Set a breakpoint in the IDE and check it.

Hi Konstantin,
Here is the codes:

Entity (Header)


import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Column;
import com.haulmont.cuba.core.entity.StandardEntity;
import com.haulmont.chile.core.annotations.Composition;
import com.haulmont.cuba.core.entity.annotation.OnDelete;
import com.haulmont.cuba.core.global.DeletePolicy;
import java.math.BigDecimal;
import java.util.Set;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import com.haulmont.chile.core.annotations.NamePattern;
import java.util.Date;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import com.haulmont.cuba.core.entity.annotation.Listeners;
import java.util.List;

/**
 * @author Mortoza
 */
@Listeners({"inteaccgms_JournalHeaderBean", "inteaccgms_JournalHeaderBean"})
@NamePattern("%s %s|journalNumber,description")
@Table(name = "INTEACCGMS_JOURNAL_HEADER")
@Entity(name = "inteaccgms$JournalHeader")
public class JournalHeader extends StandardEntity {
    private static final long serialVersionUID = 2478827267578850775L;

    @Column(name = "JOURNAL_NUMBER")
    protected Long journalNumber;

    @Temporal(TemporalType.DATE)
    @Column(name = "TRAN_DATE", nullable = false)
    protected Date tranDate;

    @Column(name = "DESCRIPTION")
    protected String description;


    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "FINA_YEAR_ID")
    protected FinancialYear finaYear;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "PERIOD_ID")
    protected FinancialPeriod period;

    @Column(name = "TOTAL_DEBIT")
    protected BigDecimal totalDebit;

    @Column(name = "TOTAL_CREDIT")
    protected BigDecimal totalCredit;


    @Composition
    @OnDelete(DeletePolicy.CASCADE)
    @OneToMany(mappedBy = "glJournalHeader")
    protected List<JournalDetail> journalDetail;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "CURRENCY_ID")
    protected Currency currency;

    @Column(name = "POSTED")
    protected Boolean posted = false;

    @Column(name = "READY_FOR_POSTING")
    protected Boolean readyForPosting = false;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "COMPANY_ID")
    protected Company company;

    public List<JournalDetail> getJournalDetail() {
        return journalDetail;
    }

    public void setJournalDetail(List<JournalDetail> journalDetail) {
        this.journalDetail = journalDetail;
    }


    public void setCompany(Company company) {
        this.company = company;
    }

    public Company getCompany() {
        return company;
    }


    public FinancialPeriod getPeriod() {
        return period;
    }

    public void setPeriod(FinancialPeriod period) {
        this.period = period;
    }


    public void setPosted(Boolean posted) {
        this.posted = posted;
    }

    public Boolean getPosted() {
        return posted;
    }

    public void setReadyForPosting(Boolean readyForPosting) {
        this.readyForPosting = readyForPosting;
    }

    public Boolean getReadyForPosting() {
        return readyForPosting;
    }


    public void setCurrency(Currency currency) {
        this.currency = currency;
    }

    public Currency getCurrency() {
        return currency;
    }


    public void setTranDate(Date tranDate) {
        this.tranDate = tranDate;
    }

    public Date getTranDate() {
        return tranDate;
    }



    public void setFinaYear(FinancialYear finaYear) {
        this.finaYear = finaYear;
    }

    public FinancialYear getFinaYear() {
        return finaYear;
    }

    public void setJournalNumber(Long journalNumber) {
        this.journalNumber = journalNumber;
    }

    public Long getJournalNumber() {
        return journalNumber;
    }

    public void setTotalCredit(BigDecimal totalCredit) {
        this.totalCredit = totalCredit;
    }

    public BigDecimal getTotalCredit() {
        return totalCredit;
    }

    public void setTotalDebit(BigDecimal totalDebit) {
        this.totalDebit = totalDebit;
    }

    public BigDecimal getTotalDebit() {
        return totalDebit;
    }
    public void setDescription(String description) {
        this.description = description;
    }

    public String getDescription() {
        return description;
    }
}

Detail entity


import javax.persistence.Entity;
import javax.persistence.Table;
import java.math.BigDecimal;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import com.haulmont.cuba.core.entity.StandardEntity;
import com.haulmont.chile.core.annotations.NamePattern;

/**
 * @author Mortoza
 */
@NamePattern("%s |glAccounts")
@Table(name = "INTEACCGMS_JOURNAL_DETAIL")
@Entity(name = "inteaccgms$JournalDetail")
public class JournalDetail extends StandardEntity {
    private static final long serialVersionUID = -4142076474086793828L;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "GL_ACCOUNTS_ID")
    protected GlAccounts glAccounts;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "GL_ACCOUNTS_SUB_ID")
    protected GlAccountsSub glAccountsSub;

    @Column(name = "REFERENCE", length = 100)
    protected String reference;

    @Column(name = "DEBIT")
    protected BigDecimal debit;

    @Column(name = "CREDIT")
    protected BigDecimal credit;



    @Column(name = "EXCHANGE_RATE", precision = 19, scale = 4)
    protected BigDecimal exchangeRate;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "GL_JOURNAL_HEADER_ID")
    protected JournalHeader glJournalHeader;

    public JournalHeader getGlJournalHeader() {
        return glJournalHeader;
    }

    public void setGlJournalHeader(JournalHeader glJournalHeader) {
        this.glJournalHeader = glJournalHeader;
    }


    public GlAccountsSub getGlAccountsSub() {
        return glAccountsSub;
    }

    public void setGlAccountsSub(GlAccountsSub glAccountsSub) {
        this.glAccountsSub = glAccountsSub;
    }

    public void setReference(String reference) {
        this.reference = reference;
    }

    public String getReference() {
        return reference;
    }

    public void setGlAccounts(GlAccounts glAccounts) {
        this.glAccounts = glAccounts;
    }

    public GlAccounts getGlAccounts() {
        return glAccounts;
    }

    public void setExchangeRate(BigDecimal exchangeRate) {
        this.exchangeRate = exchangeRate;
    }

    public BigDecimal getExchangeRate() {
        return exchangeRate;
    }

    public void setDebit(BigDecimal debit) {
        this.debit = debit;
    }

    public BigDecimal getDebit() {
        return debit;
    }

    public void setCredit(BigDecimal credit) {
        this.credit = credit;
    }

    public BigDecimal getCredit() {
        return credit;
    }


}

Listener


package com.inteacc.gms.listener;

import com.haulmont.cuba.core.Persistence;
import com.haulmont.cuba.core.Transaction;
import com.haulmont.cuba.core.TypedQuery;
import com.haulmont.cuba.core.app.UniqueNumbersService;
import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.core.listener.BeforeInsertEntityListener;
import com.inteacc.gms.entity.GlAccountsBalance;
import com.inteacc.gms.entity.JournalDetail;
import com.inteacc.gms.entity.JournalHeader;

import javax.inject.Inject;


import org.springframework.stereotype.Component;
import com.haulmont.cuba.core.listener.AfterUpdateEntityListener;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import com.haulmont.cuba.core.listener.BeforeUpdateEntityListener;

/**
 * @author Mortoza
 */
@Component("inteaccgms_JournalHeaderBean")
public class JournalHeaderListener implements BeforeInsertEntityListener<JournalHeader>, BeforeUpdateEntityListener<JournalHeader> {

    @Inject
    private UniqueNumbersService unService;
    @Inject
    private Persistence persistence;

    @Inject
    private Metadata metadata;

    @Override
    public void onBeforeInsert(JournalHeader entity) {
        entity.setJournalNumber(unService.getNextNumber("Journal_Number"));

    }



    @Override
    public void onBeforeUpdate(JournalHeader entity) {
        if (entity.getPosted() == true) {
            postEntries(entity);
        }
    }

    //@Override
    @Transactional
    public void postEntries(JournalHeader entity) {

        try (Transaction tx = persistence.createTransaction()) {
            TypedQuery<JournalDetail> detailQuery = persistence.getEntityManager().createQuery("select e from inteaccgms$JournalDetail e " +
                    "where e.glJournalHeader.id = ?1 ", JournalDetail.class); //and c.workShift.id = ?2 and c.capacityUnit=?3     glJournalHeader.id
            detailQuery.setParameter(1, entity.getId());
            List<JournalDetail> details = detailQuery.getResultList();

            for (JournalDetail detail : details) {

                GlAccountsBalance balance = metadata.create(GlAccountsBalance.class);

                balance.setCompany(entity.getCompany());
                balance.setFinancialPeriod(entity.getPeriod());
                balance.setFinancialYear(entity.getFinaYear());
                balance.setGlAccounts(detail.getGlAccounts());
                balance.setGlAccountsSub(detail.getGlAccountsSub());
                balance.setCredit(detail.getCredit());
                balance.setDebit(detail.getDebit());

                persistence.getEntityManager().persist(balance);
            }
            tx.commit();
        }
 }
 }

What about my suggestions?
1) Clean your BeforeUpdate listener from transaction management code, and check again. If the problem persists, provide the source code of your entities and the listener.
2) Ensure that your listener is invoked twice. Set a breakpoint in the IDE and check it.

Hi Konstantin,
I have create a sample project for this as attached. Thanks for your help in advance. Unfortunately, the is no updates done by the listener in the target entity, main entity is updated though.

Mortoza

sample-listeners.zip (529.3K)

ok, I have resolved it. thanks.

I have the same this problem. Could you share your resolved solution?