2014-09-27 71 views
0

JPA樹價值傳播/合併

@Entity 
public class Node 
{ 
    @ManyToOne 
    private Node parent; 

    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true) 
    private List<Node> children; 

    @ManyToMany 
    private List<Owner> ownerList; 

    ... 
} 

,我想owner小號傳播到孩子們在堅持/合併。規則是:

Any node must have at least its parent node owners 

我試圖

@PreUpdate 
public void propagateOwnersTopDown(Node node) 
{ 
    for(Node child : node.getChildren()) 
    { 
     for(Owner owner : node.getOwnerList()) 
     { 
      if(!child.getOwnerList().contains(owner)) 
      { 
       child.getOwnerList().add(owner); 
      } 
     } 
    } 
} 

,要麼

@PreUpdate 
public void propagateOwnersBottomUp(Node node) 
{ 
    if(node.getParent() == null) return; 

    for(Owner owner : node.getParent().getOwnerList()) 
    { 
     if(!node.getOwnerList().contains(owner)) 
     { 
      node.getOwnerList().add(owner); 
     } 
    } 
} 

即使我知道這是不合法的,而事實上,這些不工作(​​調用只在根上)。

我知道可以

  • 寫信addOwner()方法,其傳播所有者兒童
    • 但如果一些其他的代碼調用node.getOwnerList().add(owner)傳播被搗毀

  • 顯式調用propagateOwnersTopDown()或類似之前em.merge(node)(通常在一個事務中)
    • 但我必須把它添加到每一個EJB /交易方法

我不知道是否有一些巧妙的方式來完成這一點。

我不是數據庫專家,但它可以實現與存儲過程/觸發器/任何東西的一致性?

如果爲true,是否可以/合法地調用程序/觸發器/ @PrePersist/​​中的任何內容?

我在EclipseLink 2.5.2和MySQL 5.6上

謝謝。

+1

的EclipseLink 2.5.2具有JPA 2.1。 – Tiny 2014-09-27 10:56:57

+0

你說得對。謝謝。 – 2014-09-27 10:57:43

回答

0

我實現我自己的監聽器子系統:

protected <T extends AbstractEntity> void invokeListeners(T entity, Class<? extends Annotation> annotation) 
{ 
    ServiceListeners serviceListeners = entity.getClass().getAnnotation(ServiceListeners.class); 
    if(serviceListeners != null) 
    { 
     try 
     { 
      for(Class<?> listenerClass : serviceListeners.value()) 
      { 
       Object instance = listenerClass.newInstance(); 

       Set<Method> methods = ReflectionUtils.getAllMethods(listenerClass, ReflectionUtils.withAnnotation(annotation)); 
       for(Method m : methods) 
       { 
        m.invoke(instance, entity); 
       } 
      } 
     } 
     catch(Exception e) 
     { 
      throw new RuntimeException(e.getMessage(), e); 
     } 
    } 
} 

public <T extends AbstractEntity> void create(T entity) 
{ 
    invokeListeners(entity, OnCreate.class); 

    em.persist(entity); 
} 

public <T extends AbstractEntity> T update(T entity) 
{ 
    invokeListeners(entity, OnUpdate.class); 

    T entity2 = em.merge(entity); 
    em.flush(); 
    em.refresh(entity2); 

    return entity2; 
}