单向ManyToOne:为什么使用CascadeType.ALL保存瞬态实例但不保存CascadeType.PERSIST

时间:2014-05-07 14:45:35

标签: hibernate jpa jpa-2.0 cascade hibernate-cascade

当我尝试运行以下代码时,我收到org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: safu.Publisher异常:

public class SafuClient {
    public static void main(String[] args) {

        Session session = HibernateUtil.getSessionFactory().openSession();
        session.beginTransaction();

            Publisher publisher = new Publisher("ABC", "ABC Co.");
            Book book = new Book("1-932394-88-5", "Safu", publisher);

            session.save(book);        

            session.getTransaction().commit();

    }
}

我与书籍之间存在多对一的关系。书籍和出版商实体如下:


@Entity
public class Book {

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

    @ManyToOne(cascade={CascadeType.PERSIST})
    @JoinColumn(name="publisher_id")
    private Publisher publisher;    

    public Book() {}
    public Book(String isbn, String name, Publisher publisher) {
        this.isbn = isbn;
        this.name = name;
        this.publisher = publisher;
    }

}

@Entity
public class Publisher {

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

    public Publisher() {}
    public Publisher(String code, String name) {
        this.code = code;
        this.name = name;
    }

}

如果我将@ManyToOne(cascade={CascadeType.PERSIST})替换为@ManyToOne(cascade={CascadeType.ALL})实体中的Book,一切正常。

有人可以解释为什么会这样吗?

2 个答案:

答案 0 :(得分:1)

尝试session.persist(book);这解决了问题而不是session.save(book);

答案 1 :(得分:1)

session.save(book)方法的工作原理是从cascade={CascadeType.PERSIST}实体中的@ManyToOne注释中删除级联属性(Book)并在发布商字段中添加@Cascade (value=CascadeType.SAVE_UPDATE)代替。

@Cascade (value=CascadeType.SAVE_UPDATE)使用Hibernate的原生注释。


按照更新的Book.java工作:


@Entity
public class Book {

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

    @ManyToOne
    @JoinColumn(name="publisher_id")
    @Cascade(value=CascadeType.SAVE_UPDATE)
    private Publisher publisher;    

    public Book() {}
    public Book(String isbn, String name) {
        this.isbn = isbn;
        this.name = name;
    }   
    public Book(String isbn, String name, Publisher publisher) {
        this.isbn = isbn;
        this.name = name;
        this.publisher = publisher;
    }   
}