2014-09-27 3 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); 
     } 
    } 
} 

, даже если я знаю, что это не законно, а на самом деле, они не работают (@PreUpdate вызывается только по корню).

Я знаю, что могу

  • написать addOwner() метод, распространяющуюся владельца для детей
    • , но если какой-либо другой код вызывает node.getOwnerList().add(owner) распространения является лопнул

или

  • явно вызвать propagateOwnersTopDown() или что-то вроде как раз перед em.merge(node) (как правило, когда внутри транзакции)
    • , но я должен добавить это к каждому EJB/транзакционного метода

Интересно, есть ли какая-то отличный способ для этого.

Я не эксперт по БД, но возможно ли достичь согласованности с хранимой процедурой/триггером/чем-нибудь?

Если это правда, можно ли/законно использовать процедуру/триггер/что-нибудь в @PrePersist/@PreUpdate?

Я на EclipseLink 2.5.2 и MySQL 5.6

Спасибо.

+1

EclipseLink 2.5.2 имеет JPA 2.1. – Tiny

+0

Вы правы. Благодарю. –

ответ

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