通过未标记为 cascade PERSIST 的关系找到了一个新对象
Posted
技术标签:
【中文标题】通过未标记为 cascade PERSIST 的关系找到了一个新对象【英文标题】:a new object was found through a relationship that was not marked cascade PERSIST 【发布时间】:2012-07-28 23:31:59 【问题描述】:在尝试获得Article
和HeaderField
之间的@OneToMany
关系时,我的映射可能不太正确,导致:
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)
文章:
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;
标头字段:
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;
实体已更新以反映使用CascadeType.PERSIST
的建议,这似乎可以修复该特定错误消息。我正在努力生成更有用的日志来跟踪正在发生的事情。
【问题讨论】:
【参考方案1】:JPA 默认不提供级联功能。所以在我的情况下,级联注释丢失了,所以我用@ManyToOne
注释定义了它。请与@ManyToOne
一起定义级联类型
例如:
@ManyToOne(cascade = CascadeType.PERSIST)
private Article article = new Article();
【讨论】:
【参考方案2】:我删除了级联属性,它对我有用:
OneToMany(mappedBy = "article")
private List<HeaderField> someOrAllHeaderFields = new ArrayList<>();
【讨论】:
【参考方案3】:只需在您的关系上添加 CascadeType.ALL
OneToMany(mappedBy = "article", cascade = CascadeType.ALL)
private List<HeaderField> someOrAllHeaderFields = new ArrayList<>();
【讨论】:
【参考方案4】:您可能已经创建了 Article 的新实例和 HeaderField 的一些新实例。然后将 HeaderField 的这些实例与 Article 相关联。
之后尝试持久化文章失败,因为如错误消息所述,它指的是新对象并且关系未标记为 PERSIST。此外,根据您的日志,这些 HeaderField 实例没有设置 headerName 和 headerValue。
你有两个选择:
-
通过 em.persist 保留文章中引用的其他实例
从文章到 HeaderFields 的级联持久化操作
OneToMany(mappedBy = "article", cascade = CascadeType.PERSIST)
private List<HeaderField> someOrAllHeaderFields = new ArrayList<>();
此外,您不应删除无参数构造函数。 JPA
实现总是在创建实例时调用此构造函数。
但是你可以让无参数的构造函数受到保护。在 JPA 2.0 规范中,这是用下面的话告诉我们的:
实体类必须有一个无参数的构造函数。实体类可以 还有其他构造函数。无参数构造函数必须是公共的 或受保护。
【讨论】:
哇!必须将cascade = CascadeType.PERSIST
添加到两个实体,或至少添加到HeaderField
。
我不明白为什么添加 CascadeType.PERSIST 有效,但 CascadeType.ALL 无效。 CascadeType.ALL 包含所有其他类型,CascadeType.PERSIST 也对吗?
我想在 Pk 中保留一个空值,并且抛出相同的错误,为什么? @OneToMany(cascade = CascadeType.ALL, mappedBy = "llegadaIsla", fetch = FetchType.LAZY)。 @JoinColumn(name = "llegada_isla", referencedColumnName = "codigo") @ManyToOne 私有目录 llegadaIsla;如果我更改 CascadeType.PERSIST 不起作用。
子实体的构造函数是这样的: public public BoletoAereo() this.origenContinente= new Catalogo(); this.llegadaIsla=新目录(); this.origenIsla=新目录(); this.llegadaContinente=新目录(); this.temporada=新目录();
关键是把CAscadeType.PERSIST放在连接的2个类中以上是关于通过未标记为 cascade PERSIST 的关系找到了一个新对象的主要内容,如果未能解决你的问题,请参考以下文章
JPA,已经持久化的对象给出了“通过未标记级联 PERSIST 的关系找到了一个新对象”
Hibernate 一对一对多多对多注解cascade属性的总结