Foontik
Foontik

Reputation: 11

JPA how to persist parent in bi-directional ManyToOne

I have Payment entity with bi-directional ManyToOne releshionship to Account.

@Table(name="account")
public class Account implements Serializable { 

    //bi-directional many-to-one association to Payment
    @OneToMany(mappedBy="account",fetch=FetchType.EAGER)
    private List<Payment> payments;

@Table(name="payment")
public class Payment implements Serializable { 

    //bi-directional many-to-one association to Account
    @ManyToOne(cascade={CascadeType.MERGE},fetch=FetchType.EAGER)
    @JoinColumn(name="idAcc")
    private Account account;

Account entity was persisted. And I see information about that in the browser and in database:

Account [idAcc=475, account=12345678901230, isLock=N, rest=10000.5]

Then I need to persist child (Payment entity) and simultaneously change Account entity (change account rest). I use this code.

    public class GenericDaoImpl<T> implements GenericDao<T> {

        protected Class<T> type; 
        protected EntityManagerFactory emf = null;

        public GenericDaoImpl(Class<T> type, EntityManagerFactory emf) { 
            this.emf = emf;
            this.type = type;       
        } 

        @Override
        public void create(T entity) throws Exception { 
            EntityManager em = null; 
            try { 
                em = getEntityManager();
                em.getTransaction().begin();  
                em.persist(entity); 
                em.getTransaction().commit(); 
            } 
...
@Override
    public T findById(String id) {
         EntityManager em = getEntityManager();
            try {
                Query query = em.createNamedQuery(type.getSimpleName()+".findByName");
                query.setParameter("id", id);
                return (T)query.getSingleResult();
            } finally {
                em.close();
            }
    }

And

daoPayments = new GenericDaoImpl(Payment.class,factory); 
            Payment payment = null;
                try {
                    payment = new Payment();
                    payment.setDescription("Shop 'Pirasmani'");
                    payment.setSumm(50.25);
                        Account account = (Account)daoAccount.findById(listAccount.get(0).getIdAcc());
                        account.setRest(account.getRest()-payment.getSumm());
                        payment.setAccount(account);
                        account.getPayments().add(payment);

                    daoPayments.create(payment);
                    //print result 
                    Payment paymentMerged = (Payment)daoPayments.read(payment);
                    out.println(paymentMerged.toString()+"<br>"); 

Then I see in the browser that account rest was changed:

Payment [idPmnt=91, description=Shop 'Pirasmani', summ=50.25, account=Account [idAcc=475, account=12345678901230, isLock=N, rest=9950.25]]

But in database there is no changes in account rest. It steel is =10000.5. What am I doing wrong? Thanks.

Upvotes: 0

Views: 1114

Answers (1)

JB Nizet
JB Nizet

Reputation: 691715

You shouldn't start and stop transactions in the DAO methods. All the code in the last section should be in a single transaction, which would allow you to

  • work on attached entities, and have all the changes made on the account persisted automatically
  • remove the unnecessary cascade={CascadeType.MERGE} on the association
  • leave the database in a coherent state and not, as now, in a state where the payment has been created but the rest has not been decreased (which is why we use transactions in the first place).

That said, you persist a payment. Why would that cause any modification of its account? The only cascade you have is MERGE, and you're not doing any merge in the code.

Upvotes: 2

Related Questions