a new object was found through a relationship that was not marked cascade PERSIST

Thufir picture Thufir · Jul 31, 2012 · Viewed 74.1k times · Source

In trying to get a @OneToMany relationship between Article and HeaderField I probably have the mapping not quite right, resulting in:

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;
    }
}

The entities have been updated to reflect suggestion to use CascadeType.PERSIST which, seemingly, would fix that particular error message. I'm working on generating a more useful log to trace what's happening.

Answer

Mikko Maunu picture Mikko Maunu · Jul 31, 2012

What you had likely done is that you created new instance of Article and and some new instance(s) of HeaderField. These instance(s) of HeaderField were then associated with Article.

After that trying to persist Article fails, because as error message says, it refers to new objects and relationship is not marked as PERSIST. Additionally according your logs these instances of HeaderField does not have headerName and headerValue set.

You have two options:

  1. persist also other instances referenced from Article via em.persist
  2. cascade persist operation from Article to HeaderFields with following

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

Additionally you should not remove no-arg constructor. JPA implementation always calls this constructor when it creates instance.

But you can make no-arg constructor protected. In JPA 2.0 specification this is told wit following words:

The entity class must have a no-arg constructor. The entity class may have other constructors as well. The no-arg constructor must be public or protected.