JPA com JTA: Persistir entidades e mesclar entidades filho em cascata

Eu tenho um relacionamento um-para-muitos bidirecional com as seguintes classes de entidade:

0 ou 1 cliente <-> 0 ou mais pedidos de produtos

Ao persistir a entidade de cliente, quero que as entidades de ordem de produto associadas também sejam mantidas (como sua chave estrangeira para o cliente "pai" pode ter sido atualizada).

Claro que todas as opções necessárias do CASCADE são definidas no lado do cliente. Masele não funciona se um cliente recém-criado for persistido pela primeira vez ao fazer referência a um pedido de produto existente como neste cenário:

A ordem do produto '1' é criada e persistida. Funciona bem.o cliente '2' é criado e a ordem do produto '1' é adicionada à lista de pedidos do produto. Então é persistido. Não funciona.

Eu tentei várias abordagens, mas nenhuma delas mostrou o resultado esperado. Veja os resultados abaixo. Eu li todas as perguntas relacionadas aqui, mas elas não me ajudaram. Eu uso EclipseLink 2.3.0, puro JPA 2.0 Anotações e JTA como tipo de transação em um banco de dados na memória do Apache Derby (JavaDB) no GlassFish 3.1.2. Os relacionamentos de entidades são gerenciados por uma GUI do JSF. O gerenciamento de relacionamento em nível de objeto funciona (além de persistir), eu testei com testes JUnit.

Abordagem 1) "Padrão" (com base nos modelos de classe do 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
}

ProductOrder:

@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 de Persistência Genérica:

// 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 () lança essa exceção imediatamente:

Aviso: Ocorreu uma exceção do sistema durante uma chamada no método EJB ClientFacade public void javaee6test.beans.AbstractFacade.create (java.lang.Object) javax.ejb.EJBException: Transação anulada ...

Causado por: javax.transaction.RollbackException: Transação marcada para reversão. ...

Causado por: Exceção [EclipseLink-4002] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DatabaseException Exceção interna: java.sql.SQLIntegrityConstraintViolationException: O estado-da-sessão foi anulado porque seria causou um valor de chave duplicado em uma restrição de chave única ou primária ou índice exclusivo identificado por 'SQL120513133540930' definido em 'PRODUCTORDER'. Código de erro: -1 Chamada: INSERT INTO PRODUCTORDER (ID, CLIENT_ID) VALUES (?,?) Bind => [limite de 2 parâmetros] Consulta: InsertObjectQuery (javaee6test.model.ProductOrder [id = 1]) ...

Causada por: java.sql.SQLIntegrityConstraintViolationException: A instrução foi anulada porque teria causado um valor de chave duplicado em uma restrição de chave primária ou exclusiva ou um índice exclusivo identificado por 'SQL120513133540930' definido em 'PRO-DUCTORDER'. ...

Causada por: org.apache.derby.client.am.SqlException: A instrução foi anulada porque ela teria causado um valor de chave duplicado em uma configuração de chave exclusiva ou primária ou índice exclusivo identificado por 'SQL120513133540930' definido em ' PRODUCTOR-DER '.

Eu não entendo essa exceção. edit () funciona bem. MAS gostaria de adicionar pedidos de produtos a um cliente no momento da criação, portanto, isso é insuficiente.

Abordagem 2) mesclagem () somente

Alterações na Fachada de Persistência 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:

Em create (), a saída do EclipseLink Logging diz:

Fine: INSERT INTO CLIENT (ID, NOME, ADDRESS_ID) VALORES (?,?,?) Bind => [3 parâmetros ligados]

mas NÃO "UPDATE" na tabela de pedidos do produto. Assim, o relacionamento não é estabelecido. Novamente, edit (), por outro lado, funciona bem.

Apporach 3) Id GenerationType.IDENTITY em ambos os tipos de entidade

Alterações na classe de pedido do cliente e do produto:

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

Resultado:

Em create (), a saída do EclipseLink Logging diz:

Fine: INSERT INTO CLIENT (NOME, ADDRESS_ID) VALUES (?,?) Bind => [2 parâmetros ligados]

Bem: valores IDENTITY_VAL_LOCAL ()

Bem: INSERT INTO PRODUCTORDER (ORDADO, CLIENT_ID) VALUES (?,?) Bind => [2 parâmetros ligados]

Bem: valores IDENTITY_VAL_LOCAL ()

assim, em vez de estabelecer uma relação com a ordem do produto adicionada à lista do cliente, uma nova entidade de ordem de produção é criada e persistida (!) e um relacionamento com essa entidade é estabelecido. O mesmo aqui, edit () funciona bem.

Apporach 4) Abordagem (2) e (3) combinada

Resultado: o mesmo que a abordagem (2).

Minha pergunta é:Existe alguma maneira de perceber o cenário descrito acima? Como pode ser arquivado? Eu gostaria de ficar com o JPA (sem solução específica do fornecedor).

questionAnswers(4)

yourAnswerToTheQuestion