2

I am using Cuba Framework with Java JPQL

I have a relationship of:

  1. Transaction_Sets
  2. Transactions

Where

Transaction Entity
      @ManyToOne
        @JoinColumn(name = "TRANSACTION_SET_ID")
        @OnDelete(DeletePolicy.DENY)
        protected Transaction_Set transaction_Set;
Transaction_Set entity  
        @OneToMany(mappedBy = "transaction_Set", cascade = CascadeType.REMOVE)
        @OnDeleteInverse(DeletePolicy.DENY)
        protected List<Transaction> transactions;

I have tried many combinations of @ but for some reason it is not working. All I want it to do is:

  1. Stop the deletion of a transaction if it belongs to a Transaction_Set.
    Whenever I try and delete the transaction it deletes it and removes it from the transaction_set.
  2. Delete all transactions of a transaction_set when the transacion_set is deleted.

Number (2) is working. Number (1) I can't solve...

Have been pulling my hair out over this for the past day.

Am I going about this right? I think it might be something to do with how the Cuba Framework is set up.

Daryn
  • 1,551
  • 1
  • 15
  • 21

1 Answers1

1

An obvious setup would be the following:

// Transaction
@OnDelete(DeletePolicy.DENY)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TRANSACTION_SET_ID")
protected TransactionSet transactionSet;

// TransactionSet
@OnDelete(DeletePolicy.CASCADE) // won't work
@OneToMany(mappedBy = "transactionSet")
protected List<Transaction> transactions;

But it won't work because your requirements are contradictory: DENY policy on Transaction will prevent CASCADE deletion from the TransactionSet side. Probably the problem cannot be solved on the ORM level with @OnDelete and @OnDeleteInverse annotations, but you can implement one of the restrictions in an AfterDeleteEntityListener which is run when ORM has already done all its job.

So the mapping should be as follows (keep only the first restriction):

// Transaction
@OnDelete(DeletePolicy.DENY)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TRANSACTION_SET_ID")
protected TransactionSet transactionSet;

// TransactionSet
@OneToMany(mappedBy = "transactionSet")
protected List<Transaction> transactions;

And the entity listener (unfortunately you have to use plain SQL here):

package com.company.sample.listener;

import com.haulmont.bali.db.QueryRunner;
import com.haulmont.cuba.core.Persistence;
import com.haulmont.cuba.core.global.TimeSource;
import com.haulmont.cuba.core.global.UserSessionSource;
import com.haulmont.cuba.core.sys.persistence.DbTypeConverter;
import org.springframework.stereotype.Component;
import com.haulmont.cuba.core.listener.AfterDeleteEntityListener;
import java.sql.Connection;
import java.sql.SQLException;

import com.company.sample.entity.TransactionSet;

import javax.inject.Inject;

@Component("sample_TransactionSetEntityListener")
public class TransactionSetEntityListener implements AfterDeleteEntityListener<TransactionSet> {

    @Inject
    private TimeSource timeSource;

    @Inject
    private UserSessionSource userSessionSource;

    @Inject
    private Persistence persistence;

    @Override
    public void onAfterDelete(TransactionSet entity, Connection connection) {
        QueryRunner queryRunner = new QueryRunner();
        DbTypeConverter dbTypeConverter = persistence.getDbTypeConverter();
        try {
            queryRunner.update(connection,
                    "update SAMPLE_TRANSACTION set DELETE_TS = ?, DELETED_BY = ? where TRANSACTION_SET_ID = ?",
                    new Object[]{
                            dbTypeConverter.getSqlObject(timeSource.currentTimestamp()),
                            userSessionSource.getUserSession().getCurrentOrSubstitutedUser().getLoginLowerCase(),
                            dbTypeConverter.getSqlObject(entity.getId())
                    });
        } catch (SQLException e) {
            throw new RuntimeException("Error deleting related transactions ", e);
        }
    }
}
knstvk
  • 627
  • 4
  • 7