java - 如何使用 Spring Data / Hibernate 级联保持 @OneToMany 与 @EmbeddedId 的关系
问题描述
我已经看到了很多类似的问题,但还没有找到解决我所看到的问题的解决方案,所以如果这是一个多余的问题,请提前道歉。在我的情况下,我有各种类型的实体,它们每个都有自己的标签关联。所以我想要一个通用的 Tag 类,它没有自己的 id,而是由它标记的实体的 id 加上标记类型组成的 id / 复合键。为了(尝试)实现这一点,我创建了一个@Embeddable
id 类:
@Embeddable
public class TagId implements Serializable {
@Column(columnDefinition = "BINARY(16)")
private UUID parentId;
private String value;
// Getters, setters...
}
该 Id 又被 a 使用@MappedSuperclass
:
@MappedSuperClass
public class Tag {
@EmbeddedId
private TagId id;
// Other attributes, getters, setters...
}
...然后当我想标记特定实体时,例如使用 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...
}
最后,我有一个 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;
}
然后,当我尝试使用 Spring Data JPA 存储库来保存带有填充 BookTag 集合的新 Book 时repo.save(book)
,我想要的行为是保存 Book,然后将 id 复制到 BookTag 对象,然后保存这些对象。不幸的是,我在日志中看到的是 Book 按预期插入,然后运行 Tag 对象的插入,但与每个条目book_id
一样被绑定。null
我尝试了其他一些方法:
- @JoinColumn 而不是 mappedBy
- @MapsId 带有 @ManyToOne 对 BookTag 上的 Book 的引用
- @GeneratedValue 开启
parentId
没有工作,但我的语法可能是关闭的。提前感谢任何知道如何解决这个问题的人。
解决方案
对于任何想做类似事情的人,我终于找到了符合我标准的解决方案。
TagId 修改为:
@Embeddable
public class TagId<T> implements Serializable {
@ManyToOne
private T taggedEntity;
private String value;
// Getters, setters...
}
...这导致对 Tag 进行了轻微修改...
@MappedSuperClass
public class Tag<T> {
@EmbeddedId
private TagId id;
// Other attributes, getters, setters...
}
...然后是 BookTag ...
@Entity
@Table(name = "book_tag")
public class BookTag extends Tag<Book> {
// other attributes, getters, setters...
}
...最后预订:
@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.taggedEntity")
private List<BookTag> tags;
}
现在我可以将 1...* BookTags 添加到 Book 中,然后我必须在所有 BookTags 上设置 Book,但随后它是对 bookRepository.save() 的一次调用,所有内容都会级联。只使用 id 会更好,但泛型足够灵活。我将让它实现一个接口,以便 toString/hashCode/equals 可以在父级上调用 getId。
唯一的另一个缺点是我无法让@AttributeOverride 工作,所以虽然我希望我的 BookTag 表有一个 book_id 列,但 tagged_entity_id 就足够了。
推荐阅读
- node.js - Nodejs将变量从路由器文件传递到另一个路由器文件
- python - 改组张量有什么用
- r - 如何在 r 中为 elastsearch 设置 apikey
- ceph - 在内部存在不一致的对象时更改 osd
- next.js - 如何解决 NextJs Error: Failed to load / at loadComponents
- ios - 谷歌如何让同一帐户在 iOS 设备上的多个应用程序中可见?
- c++ - 我无法运行此代码来打印两点之间的距离。我只是一个初学者
- flutter - 手势检测器优先级
- java - Java - 根据传递值替换子节点 (BST)
- reactjs - 抽象通用反应类缺少道具