with unidirectional onetomany one many example ejemplo column jpa orm annotations many-to-many jpql

jpa - unidirectional - se encontró un nuevo objeto a través de una relación que no se marcó en cascada PERSIST



one to many jpa unidirectional (1)

Al tratar de obtener una relación de @OneToMany entre Article y HeaderField , probablemente el mapeo no sea del todo correcto, lo que da como resultado:

init: Deleting: /home/thufir/NetBeansProjects/USENET/build/built-jar.properties deps-jar: Updating property file: /home/thufir/NetBeansProjects/USENET/build/built-jar.properties compile: run: DEBUG: nntp: newsrc loading /home/thufir/.newsrc DEBUG: nntp: newsrc load: 1 groups in 31ms [EL Info]: 2012-07-31 02:05:05.677--ServerSession(8979162)--EclipseLink, version: Eclipse Persistence Services - 2.3.0.v20110604-r9504 [EL Info]: 2012-07-31 02:05:06.778--ServerSession(8979162)--file:/home/thufir/NetBeansProjects/USENET/build/classes/_USENETPU login successful [EL Warning]: 2012-07-31 02:05:06.903--ServerSession(8979162)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table ''usenet.HEADERFIELD'' doesn''t exist Error Code: 1146 Call: ALTER TABLE HEADERFIELD DROP FOREIGN KEY FK_HEADERFIELD_ARTICLE_ID Query: DataModifyQuery(sql="ALTER TABLE HEADERFIELD DROP FOREIGN KEY FK_HEADERFIELD_ARTICLE_ID") [EL Warning]: 2012-07-31 02:05:06.916--ServerSession(8979162)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown table ''ARTICLE'' Error Code: 1051 Call: DROP TABLE ARTICLE Query: DataModifyQuery(sql="DROP TABLE ARTICLE") [EL Warning]: 2012-07-31 02:05:07.033--ServerSession(8979162)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown table ''NEWSGROUP'' Error Code: 1051 Call: DROP TABLE NEWSGROUP Query: DataModifyQuery(sql="DROP TABLE NEWSGROUP") [EL Warning]: 2012-07-31 02:05:07.122--ServerSession(8979162)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown table ''HEADERFIELD'' Error Code: 1051 Call: DROP TABLE HEADERFIELD Query: DataModifyQuery(sql="DROP TABLE HEADERFIELD") [EL Warning]: 2012-07-31 02:05:08.921--UnitOfWork(26970615)--java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: null. Jul 31, 2012 2:05:08 AM net.bounceme.dur.usenet.driver.Main main SEVERE: null javax.persistence.RollbackException: java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: null. at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commitInternal(EntityTransactionImpl.java:102) at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:63) at net.bounceme.dur.usenet.driver.Main.persistArticle(Main.java:67) at net.bounceme.dur.usenet.driver.Main.<init>(Main.java:43) at net.bounceme.dur.usenet.driver.Main.main(Main.java:24) Caused by: java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: null. at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.discoverUnregisteredNewObjects(RepeatableWriteUnitOfWork.java:302) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.calculateChanges(UnitOfWorkImpl.java:695) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1482) at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:265) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1135) at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commitInternal(EntityTransactionImpl.java:84) ... 4 more [EL Info]: 2012-07-31 02:05:09.332--ServerSession(8979162)--file:/home/thufir/NetBeansProjects/USENET/build/classes/_USENETPU logout successful BUILD SUCCESSFUL (total time: 9 seconds)

Artículo:

package net.bounceme.dur.usenet.model; import java.io.Serializable; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.mail.Header; import javax.mail.Message; import javax.mail.MessagingException; import javax.persistence.*; @Entity public class Article implements Serializable { private static final long serialVersionUID = 1L; private static final Logger LOG = Logger.getLogger(Article.class.getName()); @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column private String subject; @OneToMany(mappedBy = "article", cascade = CascadeType.PERSIST) private List<HeaderField> headerFields = new ArrayList<>(); public Article() { } public Article(Message message) { try { subject = message.getSubject(); Enumeration e = message.getAllHeaders(); while (e.hasMoreElements()) { Header header = (Header) e.nextElement(); @SuppressWarnings("unchecked") SimpleEntry nameValue = new SimpleEntry(header.getName(), header.getValue()); HeaderField headerField = new HeaderField(nameValue); headerFields.add(headerField); } } catch (MessagingException ex) { Logger.getLogger(Article.class.getName()).log(Level.SEVERE, null, ex); } } public Long getId() { return id; } public void setId(Long id) { this.id = id; } @Override public int hashCode() { int hash = 0; hash += (id != null ? id.hashCode() : 0); return hash; } @Override public boolean equals(Object object) { // TODO: Warning - this method won''t work in the case the id fields are not set if (!(object instanceof Article)) { return false; } Article other = (Article) object; if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) { return false; } return true; } @Override public String toString() { return subject; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } }

HeaderField:

package net.bounceme.dur.usenet.model; import java.io.Serializable; import java.util.AbstractMap.SimpleEntry; import java.util.logging.Logger; import javax.persistence.*; @Entity public class HeaderField implements Serializable { private static final long serialVersionUID = 1L; private static final Logger LOG = Logger.getLogger(HeaderField.class.getName()); @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @ManyToOne private Article article = new Article(); @Column private String headerName; @Column private String headerValue; public HeaderField() { } public HeaderField(SimpleEntry nameValue) { headerName = nameValue.getKey().toString(); headerValue = nameValue.getValue().toString(); } public Long getId() { return id; } public void setId(Long id) { this.id = id; } @Override public int hashCode() { int hash = 0; hash += (id != null ? id.hashCode() : 0); return hash; } @Override public boolean equals(Object object) { // TODO: Warning - this method won''t work in the case the id fields are not set if (!(object instanceof HeaderField)) { return false; } HeaderField other = (HeaderField) object; if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) { return false; } return true; } @Override public String toString() { return "/n/nheaderName/t" + headerName + "/nheaderValue/t" + headerValue; } public String getHeaderName() { return headerName; } public void setHeaderName(String headerName) { this.headerName = headerName; } public String getHeaderValue() { return headerValue; } public void setHeaderValue(String headerValue) { this.headerValue = headerValue; } }

Las entidades se han actualizado para reflejar la sugerencia de utilizar CascadeType.PERSIST que, al parecer, arreglaría ese mensaje de error en particular. Estoy trabajando para generar un registro más útil para rastrear lo que está sucediendo.


Lo que probablemente haya hecho es crear una nueva instancia de Artículo y algunas nuevas instancias de HeaderField. Estas instancia (s) de HeaderField se asociaron luego con Article.

Después de eso, tratando de persistir, el artículo falla, porque como dice un mensaje de error, se refiere a objetos nuevos y la relación no está marcada como PERSIST. Además de acuerdo con sus registros, estas instancias de HeaderField no tienen conjunto de headerName y headerValue .

Tienes dos opciones:

  1. persistir también otras instancias a las que se hace referencia desde el artículo a través de em.persist
  2. la cascada persiste desde el Artículo hasta HeaderFields con siguiente

    OneToMany(mappedBy = "article", cascade = CascadeType.PERSIST) private List<HeaderField> someOrAllHeaderFields = new ArrayList<>();

Además, no debe eliminar el constructor no-arg. JPA implementación de JPA siempre llama a este constructor cuando crea una instancia.

Pero puedes hacer que el constructor no-arg esté protegido. En la especificación JPA 2.0 esto se dice con las siguientes palabras:

La clase de entidad debe tener un constructor no-arg. La clase de entidad también puede tener otros constructores. El constructor no-arg debe ser público o estar protegido.