【问题标题】:Hibernate: add existing child entity to new entity with OneToMany bidirectional relationship and persist it ('detached entity passed to persist')Hibernate:将现有子实体添加到具有 OneToMany 双向关系的新实体并将其持久化(“分离的实体传递给持久化”)
【发布时间】:2020-02-16 15:02:37
【问题描述】:

为了理解我为什么要保留子实体,这里是映射。

我有 Author (id, name, books) 和 Book (id, title, authors) 实体。他们的关系是多对多,因为任何作者都可能有不止一本书,而任何一本书可能有不止一个作者。我也有 BookClient (id, name,rentDate, books) - 与 Book 实体的关系是 OneToMany,因为任何客户都可以租零到多本书。

作者.java

@Table
public class Author {

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

    @Column(nullable = false)
    private String name;

    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name = "books_authors",
            joinColumns = { @JoinColumn(name = "author_id") },
            inverseJoinColumns = { @JoinColumn(name = "book_id") }
    )
    private Set<Book> books = new HashSet<>();

Book.java

@Entity
@Table
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(nullable = false, unique = true)
    private Long id;

    @Column(nullable = false)
    private String title;

    @ManyToMany(mappedBy = "books", fetch = FetchType.EAGER)
    private Set<Author> authors = new HashSet<>();

    @ManyToOne
    @JoinColumn(name = "client_id")
    private BookClient bookClient;

BookClient.java

@Entity
@Table
public class BookClient {

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

    @Column(nullable = false)
    private String name;

    @OneToMany(mappedBy = "bookClient", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    private Set<Book> books = new HashSet<>();

    private LocalDate rentDate;

幕后的一些业务逻辑:有很多不同作者写的书都保存在一些数据库中,比如图书馆。这个图书馆为客户提供书籍。任何新客户在取书时都可以在图书馆注册。

图书客户端使用实体管理器进行持久化:

@Transactional
@Repository("bookClientDao")
public class BookClientDaoImpl implements BookClientDao {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public void save(BookClient bookClient) {
        entityManager.persist(bookClient);
    }


    @Override
    public void saveOrUpdate(BookClient bookClient) {
        if(bookClient.getId() == null) {
            save(bookClient);
        } else {
            entityManager.merge(bookClient);
        }
    }
}

下面是它在代码中的外观示例:

    public static void main(String[] args) {
        ApplicationContext appContext = new ClassPathXmlApplicationContext("META-INF/context.xml");
        AuthorDao authorDao = (AuthorDao) appContext.getBean("authorDao");
        BookClientDao bookClientDao = (BookClientDao) appContext.getBean("bookClientDao");

        //Create a book and its author
        Book book = new Book();
        book.setTitle("John Doe Book the 1st");

        Author author = new Author();
        author.setName("John Doe");
        author.getBooks().add(book);
        authorDao.save(author);

        //Registering new Book Client
        BookClient bookClient = new BookClient();
        bookClient.setName("First Client");
        bookClient.getBooks().add(book);
        bookClient.setRentDate(LocalDate.now());

        book.setBookClient(bookClient);

        //book is expected to be updated by cascade
        bookClientDao.saveOrUpdate(bookClient); //'detached entity passed to persist' occurs here
    }

运行此代码后,我收到 detached entity passed to persist 异常,因为 Book 实例之前已被持久化。

Exception in thread "main" javax.persistence.PersistenceException:
org.hibernate.PersistentObjectException: detached entity passed to persist: entity.manager.example.entity.Book
...
Caused by: org.hibernate.PersistentObjectException:
detached entity passed to persist: entity.manager.example.entity.Book

如果我预先保存 BookClient,则 BookClient 和 Book 之间的连接设置正确,因为这两个实体都存在于 DB 中。但在我看来,这是一种解决方法。

是否可以创建新对象,将已持久化的实体连接到它,并通过级联更新其所有子对象来持久化该对象?

【问题讨论】:

    标签: java hibernate hibernate-onetomany


    【解决方案1】:

    在您的示例中,作者的保存操作和 bookClient 在不同的持久性上下文中执行。所以对于main方法,首先要合并保存作者时分离的书籍(到saveOrUpdate方法中)。

    是否可以创建新对象,将已持久化的实体连接到它,并通过级联更新其所有子对象来持久化该对象?

    这可能取决于您的应用程序要求和功能。在这个 main() 示例中,您似乎希望以事务方式保存所有这些实体。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-09
      • 2017-10-21
      • 1970-01-01
      • 2020-06-15
      • 2018-05-25
      • 2020-11-02
      • 1970-01-01
      • 2013-06-26
      相关资源
      最近更新 更多