Si, esto es posible. Este es un caso especial de la relación @ManyToOne
/ bidireccional estándar @OneToMany
. Es especial porque la entidad en cada extremo de la relación es la misma. El caso general se detalla en la Sección 2.10.2 de la especificación JPA 2.0 .
Aquí hay un ejemplo trabajado. Primero, la clase de entidad A
:
@Entity
public class A implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@ManyToOne
private A parent;
@OneToMany(mappedBy="parent")
private Collection<A> children;
// Getters, Setters, serialVersionUID, etc...
}
Aquí hay un main()
método aproximado que persiste en tres de esas entidades:
public static void main(String[] args) {
EntityManager em = ... // from EntityManagerFactory, injection, etc.
em.getTransaction().begin();
A parent = new A();
A son = new A();
A daughter = new A();
son.setParent(parent);
daughter.setParent(parent);
parent.setChildren(Arrays.asList(son, daughter));
em.persist(parent);
em.persist(son);
em.persist(daughter);
em.getTransaction().commit();
}
En este caso, las tres instancias de entidad deben persistir antes de confirmar la transacción. Si no persisto una de las entidades en el gráfico de relaciones entre padres e hijos, se lanza una excepción commit()
. En Eclipselink, esto es un RollbackException
detalle de la inconsistencia.
Este comportamiento es configurable a través del cascade
atributo en A
's @OneToMany
y @ManyToOne
anotaciones. Por ejemplo, si establezco cascade=CascadeType.ALL
ambas anotaciones, podría persistir con seguridad una de las entidades e ignorar las otras. Digamos que persistí parent
en mi transacción. La implementación de JPA atraviesa parent
la children
propiedad porque está marcada con CascadeType.ALL
. La implementación de JPA encuentra son
y daughter
allí. Luego persiste a ambos niños en mi nombre, aunque no lo solicité explícitamente.
Una nota más. Siempre es responsabilidad del programador actualizar ambos lados de una relación bidireccional. En otras palabras, cada vez que agrego un hijo a algún padre, debo actualizar la propiedad del padre del hijo en consecuencia. Actualizar solo un lado de una relación bidireccional es un error en JPA. Siempre actualice ambos lados de la relación. Esto está escrito de forma inequívoca en la página 42 de la especificación JPA 2.0:
Tenga en cuenta que es la aplicación la que tiene la responsabilidad de mantener la coherencia de las relaciones en tiempo de ejecución, por ejemplo, para asegurarse de que los lados "uno" y "muchos" de una relación bidireccional sean coherentes entre sí cuando la aplicación actualiza la relación en tiempo de ejecución. .
Para mí, el truco consistía en utilizar la relación de varios a varios. Suponga que su entidad A es una división que puede tener subdivisiones. Luego (omitiendo detalles irrelevantes):
Como tenía una lógica comercial extensa en torno a la estructura jerárquica y JPA (basado en el modelo relacional) es muy débil para admitirlo, presenté la interfaz
IHierarchyElement
y el oyente de entidadesHierarchyListener
:fuente
Top
es una relación. Página 93 de la especificación JPA 2.0, Entity Listeners y Callback Methods: "En general, el método de ciclo de vida de una aplicación portátil no debe invocar operaciones de EntityManager o Query, acceder a otras instancias de entidad o modificar relaciones". ¿Correcto? Avísame si me voy.