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:
- persistir también otras instancias a las que se hace referencia desde el artículo a través de em.persist
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.