tablas tabla secuencia que mapeo mapear llave foranea crear con column anotacion java jpa jpa-2.0 entity-relationship jta

tabla - que es un jpa en java



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

@SputNick, lo resolví siguiendo los pasos que se describen a continuación. Voy a utilizar el fragmento de código para demostrar lo que hice.

Tiene una entidad de Cliente - @ OneToMany y una entidad de Orden de Producto - @ ManyToOne . Lo usaré

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

para la persistencia, ya que me da flexibilidad para guardar y actualizar.

Para crear el cliente y los pedidos de productos correspondientes.

client.set..(some property to be saved); productOrder.set..(some property to be saved);

// Establecer productOrder para el cliente

List<ProductOrder> order = new ArrayList<>();

client.setOrders(order); // Tenga en cuenta que esto espera que se pase una lista

// establecer cliente para el productoOrder

productOrder.setClient(productOrder); .edit(client) or .edit(productOrder)

Tenga en cuenta que de cualquier manera podrá actualizar ambas tablas de entidades con sus cambios.

Aunque tarde, espero que ayude a alguien

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 haberse actualizado).

Por supuesto, todas las opciones de CASCADE requeridas se establecen en el lado del cliente. Pero no 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:

  1. El pedido de producto ''1'' se crea y persiste. Funciona bien.
  2. 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. Uso EclipseLink 2.3.0, anotaciones de JPA 2.0 puras 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 pruebas 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 del 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] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DatabaseException Excepción interna Estado del estado del estado de vista: java.sql.SQLIntegrityConstraintViolationException: El estado-estado del estado de ánimo era un estado. 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 principal o única 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: INSERTAR 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. Nuevamente, edit (), por otro lado, funciona bien.

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

Cambios en la clase de orden de cliente y producto:

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

Resultado:

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

Fino: INSERTE 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 pedido 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 forma 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).


Asegúrese de que está configurando ambos lados de la relación, no puede simplemente agregar el pedido al cliente, también necesita configurar el cliente del pedido. También necesitas fusionar los dos objetos que has cambiado. Si simplemente fusiona el cliente, el cliente de la orden no se fusionará (aunque su cascada hace que se fusione).

la persistencia no funciona, ya que la persistencia requiere que el objeto que se persista sea correcto para el contexto de persistencia, es decir, que no haga referencia a objetos separados, debe hacer referencia a objetos gestionados.

Tu problema viene de que te desprenda de los objetos. Si no separara los objetos, no tendría los mismos problemas. Normalmente, en JPA, creará un EntityManager, encontrará / consultará sus objetos, los editará / persistirá, cometer confirmación. No se requiere fusión.


Use la anotación de @Joincolumn en su entidad ProductOrder, consulte a continuación.

@Entity public class ProductOrder implements Serializable, ChildEntity { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @ManyToOne // owning side @JoinColumn(name = "PRODUCTORDER_ID", referencedColumnName = "ID") //write your database column names into name and referencedColumnName attributes. private Client client; // other fields, getters and setters }


Hola, tuve el mismo problema hoy, pregunto a la lista de correo de openJPA con este correo electrónico:

Hola. Tengo un problema con insertar y actualizar una referencia en la misma entidad.

Estoy intentando insertar un nuevo objeto (Examen) que tiene una referencia a otro objeto (Persona) y al mismo tiempo quiero actualizar un atributo (fecha de nacimiento) del objeto Persona. La actualización nunca sucede aunque establezco CascadeType en ALL. La única forma en que esto funciona es haciendo una persistencia y después de eso una operación de fusión. ¿Esto es normal? ¿Tengo que cambiar algo?

No me gusta la idea de una "actualización manual" utilizando la combinación en el objeto Persona porque no sé cuántos objetos (objeto secundario del examen) desea actualizar el usuario.

Entidades:

public class Exam{ @ManyToOne(cascade= CascadeType.ALL) @JoinColumn(name = "person_id") public Person person; ...... } public class Person{ private Date birthDate; @OneToMany(mappedBy = "person") private List<Exam> exams ....... } public class SomeClass{ public void someMethod(){ exam = new Exam() person.setBirthDate(new Date()); exam.setPerson(person); someEJB.saveExam(exam); } } public class someEJB(){ public void saveExam(Exam exam){ ejbContext.getUserTransaction().begin(); em.persist(exam); //THIS WORKS em.merge(exam.getPerson()); ejbContext.getUserTransaction().commit(); } }

¿Tengo que usar el método MERGE para cada objeto secundario?

Y la respuesta fue esta:

Parece que su problema es que el Examen es nuevo, sin embargo, la Persona existe y la Entidad existente se ignora al conectar en cascada la operación persistente. Creo que esto está funcionando como se esperaba.

Siempre que sus relaciones estén configuradas en CascadeType.ALL, siempre puede cambiar su em.persist (examen); para em.merge (examen) ;. Eso se encargaría de persistir en el nuevo examen, y también conectaría en cascada la llamada de fusión a la persona.

Gracias rick

Espero que esto pueda ayudarte.