1

I have a DAO with @Transactional annotation and with EntityManager inside.

Also I have a some IOC managed bean that has one transactional method inside.

And there are 2 entities with uni directional many2one -

@Entity
@Table(name = "AU_EVENT")
public class AuEvent { 
    @ManyToOne(fetch= FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "MODULE_ID")
private AuModule auModule;
}

AuModule doesnt have reference on AuEvents

I'm trying to do like this

@Async
@Transactional(propagation = Propagation.REQUIRED)
public void onEvent(String moduleName, String instanceName){
        AuModule auModule = auModuleDao.findModule(moduleName, instanceName);
        if (auModule == null) {
            auModule = new AuModule();
            auModule.setInstance(instanceName);
            auModule.setName(moduleName);
        }
//doesnt help
//auModule = auModuleDao.getEntityManager().merge(auModule);

AuEvent auEvent = new AuEvent();
auEvent.setAuModule(auModule);
auEventDao.persist(auEvent); // error here [AuModule detached]
}

As I read in https://stackoverflow.com/questions/14057333/detached-entity-passed-to-persist-error-with-onetomany-relation I tried to do in this way

@Async
@Transactional(propagation = Propagation.REQUIRED)
public void onEvent(String moduleName, String instanceName){

    AuEvent auEvent = new AuEvent();
    auEventDao.persist(auEvent);

    AuModule auModule = auModuleDao.findModule(moduleName, instanceName);
    if (auModule == null) {
        auModule = new AuModule();
        auModule.setInstance(instanceName);
        auModule.setName(moduleName);
    }
    auEvent.setAuModule(auModule);
    auEventDao.persist(auEvent); // error here [AuEvent detached]
}

SO, does anyone know how I can avoid this? PS Please don't suggest me to write DAO method like that -

public void saveEvent(AuEvent auEvent, String moduleName, String instanceName){
    log.info("saveEvent({}) called...", auEvent);
    AuModule auModule = auModuleDao.findModule(moduleName, instanceName);
    if (auModule == null) {
        auModule = new AuModule();
        auModule.setInstance(instanceName);
        auModule.setName(moduleName);
    }
    auEvent.setAuModule(auModule);
    persist(auEvent);
}

I exactly want to save event&module not inside of any DAO

Thanks

Community
  • 1
  • 1
Olegdelone
  • 189
  • 4
  • 15

2 Answers2

1

In the second example, you should not call auEventDao.persist(auEvent); in the end. auEvent is already attached so its enough that your transaction just ends.
Also you shouldn't call persist() on object which is allready persistent. You should call it only on new objects. That's also the problem in your first example.

You call persist() only once on auEvent that's right. But sometimes there's existing (already persisted, found in DB) auModule associated with this auEvent. And you marked this association with CascadeType.PERSIST. So persist() is cascaded also to existing auModule -> exception thrown.

Something like this should work:
1.

@Async
@Transactional(propagation = Propagation.REQUIRED)
public void onEvent(String moduleName, String instanceName){
        AuModule auModule = auModuleDao.findModule(moduleName, instanceName);
        if (auModule == null) {
            auModule = new AuModule();
            auModule.setInstance(instanceName);
            auModule.setName(moduleName);
        }
       AuEvent auEvent = new AuEvent();
       auEventDao.persist(auEvent); 

       auEvent.setAuModule(auModule);
       auEventDao.merge(auEvent);
}

or
2.

@Async
@Transactional(propagation = Propagation.REQUIRED)
public void onEvent(String moduleName, String instanceName){

    AuEvent auEvent = new AuEvent();
    auEventDao.persist(auEvent);

    AuModule auModule = auModuleDao.findModule(moduleName, instanceName);
    if (auModule == null) {
        auModule = new AuModule();
        auModule.setInstance(instanceName);
        auModule.setName(moduleName);
    }
    auEvent.setAuModule(auModule);
    // optioanlly you can call here - auEventDao.merge(auEvent); 
}
Ondrej Bozek
  • 10,987
  • 7
  • 54
  • 70
  • Thanks for helping me! But the only one difference i see between 1 and 2 - is the call of DAO.merge()... I can't believe that if I didn't call merge (2nd variant) auModule would be saved into DB... – Olegdelone Jun 28 '13 at 13:12
  • It should work, auEvent entity is *attached* see - http://stackoverflow.com/questions/1069992/jpa-entitymanager-why-use-persist-over-merge . I would rather prefer first option, explicitly calling merge. – Ondrej Bozek Jun 28 '13 at 13:22
  • @OndrejBozek It would be nice if the provider were smart enough to do the persist then do the merge. – Kevin Bowersox Jun 06 '14 at 23:02
0

In the onEvent() method you did not set the AuModule in the AuEvent after the if as you did in the saveEvent() method.

I hope this helps.

MoYapro
  • 119
  • 1
  • 8
  • I'm sorry it's my mistake - i didn't write it because i had to moderate my code - it's a commercial projetc. I apologizez again. – Olegdelone Jun 28 '13 at 13:08