【发布时间】: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