0

I need to delete a list of employees ignoring any integrity constraints (i.e. successfully delete the entity that doesn't related to any others yet or skip the entity that related to others) using JPA 2.0 and EJB3.0 on glassfish3.0:

I iterated on the list and call entity manager in a require_new transaction within a try/catch, I expect this will open small-nested transactions within the big transaction and I use em.flush() to force the updates.

but within iteration of a related entity it throws;

Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.4.2.v20130514-5956486): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails

and continue to the next employee but at the commit of the big transaction it rollbacks and throw the same exception!

I expect to throw/catch the exception with in the new-small transaction and commit the successfully deleted entities of the rest of the list...

do I miss anything?

EDIT:

Here is some code, the code in the Facade to call the entity manager to remove the bean, I annotate the function by required-new:

 public void deleteEmployeeData(Set<Employees> deleted) throws DatabaseException {

        Iterator itr;
        Employees emp;


        //delete unused recordes 
        try {

            itr = deleted.iterator();

            while (itr.hasNext()) {
                emp = (Employees) itr.next();
                deleteEmployee(emp);                
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("DONE");
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    private void deleteEmployee(Employees emp){
        try {
                    this.remove(emp);
                } catch (Exception ex) {
                    System.out.println(ex.getMessage());
                }

    }
Mariam A. Moustafa
  • 165
  • 1
  • 2
  • 14
  • We need to know a little it more about your model, do some entity have a relation on the entity you are removing? Did you remove that relation in the same transaction? – pdem Jun 22 '15 at 11:49
  • There is another entity that refers to the employee entity that I want to delete, for that a integrity constraint violated, my need is to keep all the employees that are referred from another entity and delete the others employees – Mariam A. Moustafa Jun 22 '15 at 11:55
  • @Ajan I edited the question by some code – Mariam A. Moustafa Jun 22 '15 at 11:57
  • 1
    Ok, this is very important and should be precised in the question: yuo do not want to ingore the constaint, but tu ignore the removal when constaints exception happens (this is not really the good approach but ..anyway) – pdem Jun 22 '15 at 12:00
  • Why do you use `@TransactionAttribute` rather than `@Transactional`? – DuncanKinnear Jun 22 '15 at 20:18
  • I think @Transactional in Spring not EJB, am I right? – Mariam A. Moustafa Jun 23 '15 at 08:11

3 Answers3

5

deleteEmployee method is not wrapped into a new transaction because you are referencing method on this. What you can do is to inject reference to the facade itself and then call deleteEmployee method on it (it should be public).

More or less something like this:

@Stateless
public class MyFacade {
    @EJB
    private MyFacade self;

   public void deleteEmployeeData(Set<Employees> deleted) throws DatabaseException {
     ...
     try {
       self.deleteEmployee(emp);
     } catch (Exception ex) {
       // ...
     }
     ...
   }

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void deleteEmployee(Employees emp) {
      this.remove(emp);
    }

}
Arek
  • 3,106
  • 3
  • 23
  • 32
1

Your problem seems to be the fact that you want to catch the transaction error programmatically within try catch but your transaction propagation is declarative ( using annotation) which usually creates a stack of proxies and handles the transaction failure through them transparently. You need to use programmatic transaction and wrap that up in your exception handling code.

Shailendra
  • 8,874
  • 2
  • 28
  • 37
1

To call local method and wrap it with new transaction,

@Stateless
public class UserFacade implements UserFacadeLocal {
@Resource
private SessionContext context;

@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
private void create(User user) {
        System.out.println("Users Count: "+count()); //invocation#1
        System.out.println("Users Count Through Context: "+context.getBusinessObject(UserFacadeLocal.class).count()); //invocation#2
    }

@Override
@TransactionAttribute(TransactionAttributeType.NEVER)
    public int count() {
        return ((Long) q.getSingleResult()).intValue();
    }
}

EJB Transactions in local method-calls

Community
  • 1
  • 1
Mariam A. Moustafa
  • 165
  • 1
  • 2
  • 14