【问题标题】:Update existing records in Hibernate ManyToMany Relation更新 Hibernate 多对多关系中的现有记录
【发布时间】:2015-10-22 16:37:09
【问题描述】:

在我的数据库中,我有两个表 BookLabel,它们之间具有 ManyToMany 关系。我已经使用 CascadeALLManyToMany 注释在 Hibernate 中成功映射了它们。

现在考虑这种情况。

当我添加带有标签列表的新书时。标签列表包含现有标签和新标签。当这本书保存在数据库中时,它会创建现有标签的重复条目。 [意味着每次创建新标签时(即使是现有标签),主键不同,而不是使用现有和更新多对多表的引用]。我希望 Hibernate 更新现有标签并创建新的。类似地,ManyToMany 表要自行更新。

我可以考虑手动解决。

  • 保存没有标签的书。
  • 将现有标签和新标签与图书标签与图书标签分开。
  • 使用session.update() 更新现有标签并使用session.save() 保存新标签
  • ManyToMany 表将自动更新。

但我相信这个解决方案涉及很少的冗长编码和不必要的处理,并且可以改进。

Hibernate 是否提供了一些内置功能来解决这个问题以及如何改进我的解决方案。

这是我的图书实体

@Entity
@XmlRootElement
public class Book {
@Id
@GeneratedValue
private int bookID;
private String bookName;
private String bookDescription;
private String bookAuthor;
private String bookEdition;
private String bookDownloadURL;
private String bookImageURL;

@ManyToMany(cascade = { CascadeType.ALL })
@JoinTable(name = "book_label", joinColumns = { @JoinColumn(name = "books_bookID") }, inverseJoinColumns = {
        @JoinColumn(name = "labels_labelID") })
private List<Label> labels = new ArrayList<Label>();
//getters and setters

标签实体

@Entity
@XmlRootElement
public class Label {

@Id
@GeneratedValue
private int labelID;
private String labelName;
private String labelDesc;
@ManyToMany(mappedBy="labels",fetch=FetchType.EAGER)
private List<Book> books = new ArrayList<Book>();
// getter and setters

在我的数据库中,我已经创建了三个表

  1. col 名称与 Book 实体的数据成员完全相同的 book 表
  2. col 名称与 Label 实体的数据成员完全相同的标签表
  3. book_label 表有两列 books_bookID、labels_labelID。这些列分别引用其他两个表中的 bookID 和 labelID(意味着它们实际上是外键)

这是我的测试用例代码

    BookDAO booksDao = new BookDAO();
    LabelDAO labelDao = new LabelDAO();

    //Label by these name exist already in database. 
    //Upon adding the new book it should use the previous label and do entries in manytomany table accordingly
    // (shouldn't create new labels with same names and map against them) <- THis is happening now 

    Label label1= new Label();
    label1.setLabelName("Fantasy");

    Label label2= new Label();
    label2.setLabelName("Literature");


    Book book1= new Book();
    book1.setBookName("Talaash");
    book1.getLabels().add(label1);
    book1.getLabels().add(label2);

    booksDao.addBook(book1);

【问题讨论】:

  • 你能告诉我们这些类以便我们看到注释吗?

标签: java hibernate jpa orm many-to-many


【解决方案1】:

如果我理解正确,您的问题是两个表都是关系的所有者,因此这会导致重复条目。只有一个类应该是关系的所有者。在你们的一堂课上尝试类似:

@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, mappedBy = "books")
public List<Label> getLabels()

并且在您的标签中,您应该有书籍列表。 同样,如果我理解正确,因为您没有提供类以便我们进行更好的分析

【讨论】:

  • 亲爱的,不,已经只有一个所有者了。重复条目是指如果我的书有已经创建的标签。它为它们创建新的标签行。如果我添加了带有文学标签的书。它将始终在标签表中创建一个新行并对其进行映射。相反,它应该使用以前的标签引用并仅更新映射表。我希望你能理解我的观点[如果没有,请告诉我,我将通过引用一个示例场景来详细解释]
  • 通过以前的参考你的意思是应该找到名称为文学的标签并使用这个。我正确吗?如是。那么这是我的正常行为,而不是错误,因为您的标签名称不是唯一标识符。您应该检索此标签并设置 book.getLabels.add(带有适当 id 的标签)。你明白我的意思吗?
  • 我知道了。非常感谢。它现在可以工作,但是当我使用session .save(book) 时它可以工作,当我使用session.persist(book) 时会出现错误org.hibernate.PersistentObjectException: detached entity passed to persist 你能解释一下吗
  • 这意味着 hibernate 不知道你试图持久化的对象。我认为一个简单而肮脏的解决方案是使用 CascadeType.Merge 而不是全部。但是要了解您需要进一步研究您的关联以及持久性是如何工作的。为了更好地向您解释,我需要查看您检索、更改和创建这些对象的所有代码。
  • 我明白你在说什么。我将研究更多关于关联的知识。再次感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-27
  • 2012-09-17
  • 1970-01-01
  • 2019-02-11
  • 2012-11-09
相关资源
最近更新 更多