2013-06-28 3 views
1

У меня есть DAO с аннотацией @Transactional и с EntityManager внутри.Отсоединенный объект JPA для сохранения

Кроме того, у меня есть некоторый управляемый bean-компонент, который имеет один транзакционный метод внутри.

И есть 2 лица с универ направленным 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 оленьей кожи есть ссылка на AuEvents

Я пытаюсь сделать как этот

@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] 
} 

Как я прочитал в https://stackoverflow.com/questions/14057333/detached-entity-passed-to-persist-error-with-onetomany-relation Я попытался сделать так

@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] 
} 

ТАК, кто-нибудь знает, как я могу избежать этого? PS Пожалуйста, не предложить мне написать метод DAO, как что -

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); 
} 

Я точно хочу, чтобы сохранить событие & модуль не внутри любого DAO

Благодарности

ответ

1

Во втором примере вы не должны звонить auEventDao.persist(auEvent); в конце. auEvent уже прилагается, поэтому его достаточно, чтобы ваша сделка заканчивалась.
Также вы не должны звоните persist() на объект, который является уже стойким. Вы должны называть его только новыми объектами. Это также проблема в вашем первом примере.

Вы звоните persist() только один раз на auEvent, это право. Но иногда существует (уже сохраняется, найденный в БД) auModule, связанный с этим auEvent. И вы отметили эту связь с CascadeType.PERSIST. Таким образом, persist() также каскадируется и к существующим auModule ->исключение брошено.

Что-то, как это должно работать:
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); 
} 

или
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); 
} 
+0

Спасибо, что помогли мне! Но единственное различие, которое я вижу между 1 и 2, - это вызов DAO.merge() ... Я не могу поверить, что если бы я не назвал merge (2-й вариант), auModule будет сохранен в DB ... – Olegdelone

+0

Он должен работать, объект auEvent * прикреплен * см. - http://stackoverflow.com/questions/1069992/jpa-entitymanager-why-use-persist-over-merge. Я предпочел бы первый вариант, явно вызывающий слияние. –

+0

Невероятно! Так работает первый вариант! Ты крут. – Olegdelone

0

В OnEvent() метод вы не установили AuModule в AuEvent после того, как это было сделано в методе saveEvent().

Надеюсь, это поможет.

+0

Я сожалею, что это моя ошибка - я не писал, потому что я должен был умеренный мой код - это коммерческий проект. Я снова извиняюсь. – Olegdelone