En essayant d'obtenir une relation @OneToMany
entre Article
et HeaderField
, le mappage n'est probablement pas tout à fait correct, ce qui entraîne:
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)
Article:
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;
}
}
Les entités ont été mises à jour pour refléter la suggestion d'utiliser CascadeType.PERSIST
qui, apparemment, permettrait de corriger ce message d'erreur particulier. Je travaille sur la génération d'un journal plus utile pour suivre ce qui se passe.
Ce que vous aviez probablement fait, c'est que vous avez créé une nouvelle instance de Article et de nouvelles instances de HeaderField. Ces instances de HeaderField ont ensuite été associées à Article.
Après cette tentative de persistance, cet article échoue car, comme le dit le message d'erreur, il fait référence à de nouveaux objets et la relation n'est pas marquée comme PERSIST. De plus, selon vos journaux, ces instances de HeaderField ne possèdent pas headerName et headerValue set.
Vous avez deux options:
cascade, opération persistante d’Article à HeaderFields avec les options suivantes
OneToMany(mappedBy = "article", cascade = CascadeType.PERSIST)
private List<HeaderField> someOrAllHeaderFields = new ArrayList<>();
De plus, vous ne devez pas supprimer le constructeur no-arg. JPA
implementation appelle toujours ce constructeur lorsqu’il crée une instance.
Mais vous pouvez faire en sorte que le constructeur sans argument soit protégé. Dans la spécification JPA 2.0, cela est dit avec les mots suivants:
La classe d'entité doit avoir un constructeur no-arg. La classe d'entité peut avoir d'autres constructeurs aussi. Le constructeur no-arg doit être public ou protégé.
ajoutez simplement CascadeType.ALL sur votre relation.
OneToMany(mappedBy = "article", cascade = CascadeType.ALL)
private List<HeaderField> someOrAllHeaderFields = new ArrayList<>();