JPA con JTA: persistir entidad y fusionar entidades secundarias en cascada

Tengo una relación bidireccional de uno a varios con las siguientes clases de entidades:

0 o 1 cliente <-> 0 o más pedidos de productos

Al persistir en la entidad del cliente, deseo que las entidades de orden del producto asociadas también se conserven (ya que su clave externa para el cliente "principal" puede haber sido actualizada).

Por supuesto, todas las opciones de CASCADE requeridas se establecen en el lado del cliente. Perono funciona si un cliente recién creado se conserva por primera vez al hacer referencia a un pedido de producto existente como en este escenario:

El pedido de producto '1' se crea y persiste. Funciona bien.el cliente '2' se crea y el pedido del producto '1' se agrega a su lista de pedidos del producto. Entonces se persiste. No funciona.

Probé varios apporaches, pero ninguno de ellos mostró el resultado esperado. Vea los resultados a continuación. Leí todas las preguntas relacionadas aquí, pero no me ayudaron. Utilizo EclipseLink 2.3.0, puras anotaciones de JPA 2.0 y JTA como tipo de transacción en un DB de memoria en memoria de Apache Derby (JavaDB) en GlassFish 3.1.2. Las relaciones entre entidades se gestionan mediante una GUI de JSF. La gestión de relaciones a nivel de objeto funciona (aparte de persistir), lo probé con las pruebas de JUnit.

Enfoque 1) "Predeterminado" (basado en plantillas de clase NetBeans)

Cliente:

@Entity
public class Client implements Serializable, ParentEntity {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @OneToMany(mappedBy = "client", cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH},
            fetch= FetchType.LAZY)
    private List<ProductOrder> orders = new ArrayList<>();

    // other fields, getters and setters
}

Orden de producto:

@Entity
public class ProductOrder implements Serializable, ChildEntity {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToOne // owning side
    private Client client;

    // other fields, getters and setters
}

Fachada genérica de persistencia:

// Called when pressing "save" on the "create new..." JSF page
public void create(T entity) {
    getEntityManager().persist(entity);
}

// Called when pressing "save" on the "edit..." JSF page
public void edit(T entity) {
    getEntityManager().merge(entity);
}

Resultado:

create () lanza esta excepción inmediatamente:

Advertencia: se produjo una excepción en el sistema durante una invocación en el método EJB ClientFacade public void javaee6test.beans.AbstractFacade.create (java.lang.Object) javax.ejb.EJBException: Transacción abortada ...

Causado por: javax.transaction.RollbackException: Transacción marcada para retrotracción. ...

Causado por: Exception [EclipseLink-4002] (Servicios de persistencia de Eclipse - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DatabaseException Excepción interna El estado-estado de ánimo fue una exención. han provocado un valor de clave duplicado en una restricción de clave única o primaria o un índice único identificado por 'SQL120513133540930' definido en 'PRODUCTORDER'. Código de error: -1 Llamada: INSERTAR EN PRODUCTORDER (ID, CLIENT_ID) VALORES (?,?) Bind => [2 parámetros enlazados] Consulta: InsertObjectQuery (javaee6test.model.ProductOrder [id = 1]) ...

Causado por: java.sql.SQLIntegrityConstraintViolationException: La declaración fue abortada porque habría causado un valor de clave duplicado en una restricción de clave única o primaria o un índice único identificado por 'SQL120513133540930' definido en 'PRO-DUCTORDER'. ...

Causado por: org.apache.derby.client.am.SqlException: la declaración fue abortada debido a que habría causado un valor de clave duplicado en una clave única o primaria o un índice único identificado por 'SQL120513133540930' definido en ' ORDEN DE PRODUCTO'.

No entiendo esta excepción. editar () funciona bien. PERO me gustaría agregar pedidos de productos a un cliente en el momento de su creación, por lo que esto es insuficiente.

Enfoque 2) fusionar () solamente

Cambios en la fachada de persistencia genérica:

// Called when pressing "save" on the "create new..." JSF page
public void create(T entity) {
    getEntityManager().merge(entity);
}

// Called when pressing "save" on the "edit..." JSF page
public void edit(T entity) {
    getEntityManager().merge(entity);
}

Resultado:

En create (), la salida del registro de EclipseLink dice:

Fino: INSERTE EN EL CLIENTE (ID, NOMBRE, DIRECCIÓN_ID) VALORES (?,?,?) Bind => [3 parámetros enlazados]

pero NO "ACTUALIZACIÓN" en la tabla de pedidos de productos. Por lo tanto, la relación no está establecida. De nuevo, edit (), por otro lado, funciona bien.

Apporach 3) Id GenerationType.IDENTITY en ambos tipos de entidades

Cambios en la clase de pedido del cliente y del producto:

...
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
...

Resultado:

En create (), la salida del registro de EclipseLink dice:

Fino: INSERTAR EN EL CLIENTE (NOMBRE, DIRECCIÓN_ID) VALORES (?,?) Bind => [2 parámetros enlazados]

Fino: valores IDENTITY_VAL_LOCAL ()

Fino: INSERTAR EN PRODUCTORDER (ORDERDATE, CLIENT_ID) VALUES (?,?) Bind => [2 parámetros enlazados]

Fino: valores IDENTITY_VAL_LOCAL ()

por lo tanto, en lugar de establecer una relación con el pedido del producto agregado a la lista del cliente, se crea y persiste una nueva entidad de orden de corte de producto (!) y se establece una relación con esa entidad. Lo mismo aquí, editar () funciona bien.

Apporach 4) Enfoque (2) y (3) combinados

Resultado: igual que el enfoque (2).

Mi pregunta es:¿Hay alguna manera de darse cuenta del escenario descrito anteriormente? ¿Cómo puede ser archivado? Me gustaría seguir con JPA (no hay una solución específica del proveedor).

Respuestas a la pregunta(4)

Su respuesta a la pregunta