当前位置: 首页 > 知识库问答 >
问题:

Hibernate:将现有子实体添加到具有OneTo在多双向关系的新实体并持久化它(“传递给持久化的分离实体”)

柯昆
2023-03-14

为了理解为什么要持久化子实体,下面是映射。

我有作者(id,姓名,书籍)和书籍(id,标题,作者)实体。他们的关系是很多的,因为任何作者可能有多个书,任何书可能有多个作者。此外,我有BookClient(id,名称,rentDate,books) - 与Book实体的关系是OneToMany,因为任何客户都可以向许多书籍租用零。

Author.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
    }

运行此代码后,我将获得分离的实体传递给持久化异常,因为 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 berforehand持久化,那个么BookClient和Book之间的连接设置正确,因为这两个实体都存在于数据库中。但在我看来,这是一种变通办法。

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

共有1个答案

羊越
2023-03-14

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

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

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

 类似资料:
  • 这个网站上没有一个类似的问题能够解决我的问题。 错误:org.hibernate.persistentobjectexception:传递给persist:healthcheckapi.model.checks的分离实体 示例JSON健康对象: 请注意,这两个对象的ID都是自动生成的,我认为这是问题的一部分。

  • 我正试图实现与hibernate的许多单向关系。问题是,当我试图向数据库中添加一些值时,我遇到了以下错误: 运行时发生异常。null:InvocationTargetException:未能执行ApplicationRunner:传递给persist:dnd35cg的分离实体。模型DND类;嵌套的异常是org。冬眠PersistentObjectException:传递给persist:dnd35

  • 我有一个实体,它已经持久化,并希望将其添加到新生成的父实体(尚未持久化)。如果我尝试持久化父级,我会得到错误“分离的实体传递到持久化:model.child”。我想我必须以某种方式为孩子调用“EntityManager.merge()”,而不是“EntityManager.persisted()”。但是我没有显式调用persisted。这由“cascade=cascadetype.all”注释处理

  • 问题内容: 我已经成功用hibernate写了我的第一个主要的孩子例子。几天后,我再次使用它并升级了一些库。不知道我做了什么,但是我再也无法使它运行了。有人可以帮助我找出返回以下错误消息的代码中的错误吗: hibernate映射: 编辑: InvoiceManager.java 发票.java InvoiceItem.java 编辑: 从客户端发送的JSON对象: 编辑: 一些详细信息: 我试图通

  • 对于新学生和新课程的情况,它工作得很好,但是在新课程和现有学生的情况下,我会从数据库中抛出一个唯一的约束冲突。关系类似于下面。 在持久化之前,我尝试使用entitymanager查找一个学生,如果该学生存在,则使用该实例而不是新的学生实例。这也不起作用,它仍然尝试执行插入而不是更新

  • 我有一个实体,它已经被持久化了,想把它添加到一个新生成的父实体(还没有持久化)。如果我尝试持久化父级,那么我会得到错误“Detached entity pass to persist:model.child”。我认为我必须以某种方式为孩子调用“EntityManager.merge()”,而不是“EntityManager.Persist()”。但我没有显式调用persist。这是由“Cascad