试图通过分离关系启动持久化实体"传递的分离实体持续存在"

时间:2014-12-24 19:28:52

标签: java hibernate jpa merge persist

我需要坚持一个具有分离关系的新实体,但是,在坚持(...)的那一刻,我得到一个例外:

Exception in thread "main" javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: model.Subject
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1214)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1147)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1153)
    at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:678)
    at Application.method3(Application.java:90)
    at Application.main(Application.java:41)
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: model.Subject
    at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:127)
    at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
    at org.hibernate.tuple.entity.AbstractEntityTuplizer$IncrediblySillyJpaMapsIdMappedIdentifierValueMarshaller.getIdentifier(AbstractEntityTuplizer.java:375)
    at org.hibernate.tuple.entity.AbstractEntityTuplizer.getIdentifier(AbstractEntityTuplizer.java:223)
    at org.hibernate.persister.entity.AbstractEntityPersister.getIdentifier(AbstractEntityPersister.java:3850)
    at org.hibernate.persister.entity.AbstractEntityPersister.isTransient(AbstractEntityPersister.java:3558)
    at org.hibernate.engine.ForeignKeys.isTransient(ForeignKeys.java:203)
    at org.hibernate.event.def.AbstractSaveEventListener.getEntityState(AbstractSaveEventListener.java:531)
    at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:102)
    at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
    at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:808)
    at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:782)
    at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:786)
    at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:672)
    ... 2 more

实体: 受试者

@Entity
@Table(name = "TAsignaturas", uniqueConstraints = { @UniqueConstraint(columnNames = {
        "nombre", "curso" }) })
public class Subject implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "seq")
    @SequenceGenerator(name = "seq", sequenceName = "ASIGNATURAS_SEQUENCE", allocationSize = 1,       initialValue = 1)
    private Long id;

    private String nombre, curso;
    private int creditos;

    // @Transient
    @OneToMany(mappedBy = "subject")
    private Set<Matricula> matriculas;

    public Subject() {
        matriculas = new HashSet<Matricula>();
    }

    public Subject(String nombre, String curso, int creditos) {
        this.setNombre(nombre);
        this.setCurso(curso);
        this.setCreditos(creditos);
        this.matriculas = new HashSet<Matricula>();
    }

    public Matricula addMatricula(Matricula m) {
        m.setSubject(this);
        this.matriculas.add(m);
        return m;
    }

    public void removeMatricula(Matricula m) {
        this.matriculas.remove(m);
    }

    [...]
}

Alumno

@Entity
public class Alumno implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private static final long serialVersionUID = 1L;

    @OneToMany(mappedBy = "alumno")
    private Set<Matricula> matriculadas;

    public Alumno() {
        super();
        this.matriculadas = new HashSet<Matricula>();
    }

    public Matricula addMatricula(Matricula m) {
        m.setAlumno(this);
        this.matriculadas.add(m);
        return m;
    }

    public void removeMatricula(Matricula m) {
        this.matriculadas.remove(m);
    }
    [...]
}

Matricula

@IdClass(MatriculaKey.class)
@Entity
public class Matricula implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @ManyToOne
    private Alumno alumno;

    @Id
    @ManyToOne
    private Subject subject;

    public Matricula() {
        super();
    }

    public Matricula(Alumno a, Subject s) {
        super();
        this.alumno = a;
        this.subject = s;
        this.alumno.addMatricula(this);
        this.subject.addMatricula(this);
    }

    public void addAlumno(Alumno a) {
        a.getMatriculadas().add(this);
        this.alumno = a;
    }

    public void removeAlumno(Alumno a) {
        a.getMatriculadas().remove(this);
        this.setAlumno(null);
    }

    public void addSubject(Subject s) {
        s._getMatriculas().add(this);
        this.subject = s;
    }

    public void removeSubject(Subject s) {
        s._getMatriculas().remove(this);
        this.setSubject(null);
    }
    [...]
}

启动例外的主要代码:

public class Application {
    Subject sub;
    public static void main(String[] args) {
        Application a = new Application();
        // method2          
        EntityManager em = Jpa.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        a.method2();
        tx.commit();
        if (em.isOpen())
            em.close();
        // method3
        em = Jpa.createEntityManager();
        tx = em.getTransaction();
        tx.begin();
        a.method2();
        tx.commit();
        if (em.isOpen())
            em.close();
    }
    //It´s necessary execute this method before to method3, in two different transactions, non in one transaction
    private void method2() {
        this.sub = Jpa.getManager().find(Subject.class, 2L);
    }

    private void method3() {
        Alumno al = new Alumno();
        Matricula m = new Matricula(al, this.sub);
        Jpa.getManager().persist(m); //error. merge doesn´t work nor
    }
}

我糟糕的解决方案的主要代码:

public class Application {
    Subject sub;
    public static void main(String[] args) {
        Application a = new Application();
        // method2          
        EntityManager em = Jpa.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        a.method2();
        tx.commit();
        if (em.isOpen())
            em.close();
        // method3
        em = Jpa.createEntityManager();
        tx = em.getTransaction();
        tx.begin();
        a.method2();
        tx.commit();
        if (em.isOpen())
            em.close();
    }

    private void method2() {
        this.sub = Jpa.getManager().find(Subject.class, 2L);
    }

    private void method3() {
        Alumno al = new Alumno();
        //aux transient subject
        Subject s=new Subject();
        Matricula m = new Matricula(al, s);
        //now, I can persist correctly
        Jpa.getManager().persist(m);
        //replace the aux subject...
        m.removeSubject(s);
        m.addSubject(sub);
        //and update
        Jpa.getManager().merge(m);
    }
}

是否存在针对此问题的更简单的解决方案?

米格尔

0 个答案:

没有答案