简体   繁体   English

如何使用 Spring Data / Hibernate 级联保持 @OneToMany 与 @EmbeddedId 的关系

[英]How do I cascade persist an @OneToMany relationship with an @EmbeddedId using Spring Data / Hibernate

I've seen a lot of similar questions asked about this but haven't found a solution that fixes the problem I'm seeing, so apologies up front if this is a redundant question.我已经看到很多类似的问题被问到,但还没有找到解决我所看到的问题的解决方案,所以如果这是一个多余的问题,请提前道歉。 In my situation I have various types of entities and they're each going to have their own tag associations.在我的情况下,我有各种类型的实体,它们每个都有自己的标签关联。 So I want a generic Tag class that won't have it's own id, but rather an id / composite key made of the id of the entity it's tagging, plus the tag type.所以我想要一个通用的 Tag 类,它不会有自己的 id,而是一个 id/复合键,由它标记的实体的 id 和标签类型组成。 To (attempt to) achieve this I made an @Embeddable id class:为了(尝试)实现这一点,我创建了一个@Embeddable id 类:

@Embeddable
public class TagId implements Serializable {

  @Column(columnDefinition = "BINARY(16)")
  private UUID parentId;
  private String value;

  // Getters, setters...

}

That Id is in turn used by a @MappedSuperclass :该 Id 反过来被@MappedSuperclass

@MappedSuperClass
public class Tag {
 
  @EmbeddedId
  private TagId id;

  // Other attributes, getters, setters...

}

... and then when I want to tag a specific entity, for example using a BookTag, the table would have a book_id column as a foreign key to a Book table taking the place of parentId : ...然后当我想标记特定实体时,例如使用 BookTag,该表将有一个book_id列作为 Book 表的外键,代替parentId

@Entity
@Table(name = "book_tag")
@AttributeOverride(name = "parentId", column = @Column(name = "book_id"))
public class BookTag extends Tag {

  // other attributes, getters, setters...

}

Then finally, I have a Book entity:最后,我有一个 Book 实体:

@Entity
@Table(name = "book")
public class Book {

  @Id
  @GeneratedValue
  @Column(columnDefinition = "Binary(16)")
  private UUID id;

  // other attributes, getters, setters...

  @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "id.parentId")
  private List<BookTag> tags;
}

When I then try to save a new Book, with a populated BookTag collection, using a Spring Data JPA repository to repo.save(book) , my desired behavior is that the Book is saved, then the id is copied to the BookTag objects, and those are saved.然后,当我尝试使用填充的 BookTag 集合保存新 Book 时,使用 Spring Data JPA 存储库repo.save(book) ,我想要的行为是保存 Book,然后将 id 复制到 BookTag 对象,那些被保存了。 Unfortunately, what I'm seeing in the log is that Book is inserted as expected, then the inserts for the Tag objects are run, but book_id is being bound as null for each of the entries.不幸的是,我在日志中看到的是 Book 按预期插入,然后运行 ​​Tag 对象的插入,但book_id被绑定为每个条目的null

I've tried a few other approaches:我尝试了其他一些方法:

  1. @JoinColumn instead of mappedBy @JoinColumn 而不是mappedBy
  2. @MapsId with a @ManyToOne reference to Book on BookTag @MapsId 带有对 BookTag 上 Book 的 @ManyToOne 引用
  3. @GeneratedValue on parentId parentId @GeneratedValue

None worked, but it is possible my syntax was off.没有任何效果,但我的语法可能已关闭。 Thanks in advance for anyone who knows how to tackle this problem.预先感谢任何知道如何解决此问题的人。

To anyone who wants to do something similar, I finally found a solution that meets my criteria.对于任何想做类似事情的人,我终于找到了符合我标准的解决方案。

TagId was modified to this: TagId 修改为:

@Embeddable
public class TagId<T> implements Serializable {

  @ManyToOne
  private T parent;
  private String value;

  // Getters, setters...

}

...which leads to a slight modification to Tag... ......这导致对标签的轻微修改......

@MappedSuperClass
public class Tag<T> {
 
  @EmbeddedId
  private TagId id;

  // Other attributes, getters, setters...

}

...and then BookTag... ...然后BookTag...

@Entity
@Table(name = "book_tag")
@AttributeOverride(name = "parent", column = @Column(name = "book_id"))
public class BookTag extends Tag<Book> {

  // other attributes, getters, setters...

}

...and finally Book: ...最后预订:

@Entity
@Table(name = "book")
public class Book {

  @Id
  @GeneratedValue
  @Column(columnDefinition = "Binary(16)")
  private UUID id;

  // other attributes, getters, setters...

  @JoinColumn(name = "book_id", referencedColumnName = "id")
  @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
  private List<BookTag> tags;
}

Now I can add 1...* BookTags to a Book, and in turn I have to set the Book on all the BookTags, but then it's one call to bookRepository.save() and everything cascades down.现在我可以将 1...* BookTags 添加到 Book,然后我必须在所有 BookTags 上设置 Book,但是这是对 bookRepository.save() 的一次调用,并且所有内容都向下级联。 It would have been nicer to just do it with an id, but a generic is flexible enough.用 id 来做会更好,但泛型足够灵活。 I'll just have it implement an interface so that toString/hashCode/equals can call getId on parent.我只会让它实现一个接口,以便 toString/hashCode/equals 可以在父级上调用 getId。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM