在merge()之后,对象仍被标记为未保存的瞬态实例

时间:2016-11-16 21:48:41

标签: java hibernate jpa exception

Library lib; //has a OneToMany rs to Book
lib = new Library();

Book book; //has a OneToMany rs to Letters
book = new Book(lib);
book.save()

book = new Book(lib);
book.merge() //.save() will throw an exception (detached entity passed to persist jpa) because of lib, so I merge it

Letters letters;
letters = new Letters(book);
letters.save(); //throws TransientPropertyValueException: object references an unsaved transient instance.

出于测试目的,我想使用相同的库创建多本书并保存。此外,我想创建多个字母,使用相同的书并存储它们。但我不知道如何实现这一目标,因为在合并(书)后,这本书不再是短暂的......

感谢

编辑:添加其他类以使事情更加清晰。

public abstract class Model implements Serializable {
/**
 * Save the current object in the database.
 *
 */
public void save() {
    EntityManager entityManager = HibernateUtil.getEntityManagerFactory().createEntityManager();
    entityManager.getTransaction().begin();
    entityManager.persist(this);
    entityManager.getTransaction().commit();
    entityManager.close();
}
/**
 * Delete the current object from the database.
 *
 */
public void delete() {
    EntityManager entityManager = HibernateUtil.getEntityManagerFactory().createEntityManager();
    entityManager.getTransaction().begin();
    entityManager.remove(entityManager.contains(this) ? this : entityManager.merge(this));
    entityManager.getTransaction().commit();
    entityManager.close();
}

public void merge(){
    EntityManager entityManager = HibernateUtil.getEntityManagerFactory().createEntityManager();
    entityManager.getTransaction().begin();
    entityManager.merge(this);
    entityManager.getTransaction().commit();
    entityManager.close();
}
}

图书实体(信函和图书馆实体看起来一样)

@Entity
@Table(name = "book")
public class Book{

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "BOOK_ID")
private Integer id;

@OneToMany(fetch = FetchType.LAZY, mappedBy = "book", cascade = {CascadeType.ALL})
private List<Letters> letters;

 @ManyToOne(fetch = FetchType.LAZY,cascade = {CascadeType.ALL})
 @JoinColumn(name = "lib_id")
 Library library;

}

1 个答案:

答案 0 :(得分:0)

@JBNizet打算说的是你需要develop better your question, make it clearer

关于你的问题,我想你有一个类似的实体结构:

实体库:

@Entity
@Table(name = "library")
public class Library {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "LIB_ID")
    private Integer id;

    @OneToMany(mappedBy = "library")
    private List<Book> books;

    // getters & setters
}

实体书:

@Entity
@Table(name = "book")
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "BOOK_ID")
    private Integer id;

    @ManyToOne
    @JoinColumn(name = "LIB_ID")
    private Library library;

    @OneToMany(mappedBy = "book")
    private List<Letters> letters;

    // ...
}

实体信函:

@Entity
@Table(name = "letters")
public class Letters {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "LETTERS_ID")
    private Integer id;

    @ManyToOne
    @JoinColumn(name = "BOOK_ID")
    private Book book;

    // ...

}

此问题通常与您cascade=CascadeType.ALL映射中@ManyToOne的缺失有关,如已说明here

但是,一旦打开会话,保存/合并每个对象然后提交/关闭它,您就必须更改关系的级联类型。这样做:

  • 将Book类中的library对象的级联类型保持为@ManyToOne(fetch = FetchType.LAZY, cascade = { CascadeType.ALL })
  • 将所有其他级联更改为CascadeType.MERGE。这样,每当JPA必须保存整个对象树时,它总是会尝试合并它们。