如何使用 Spring Data / Hibernate 级联保持 @OneToMany 与 @EmbeddedId 的关系
Posted
技术标签:
【中文标题】如何使用 Spring Data / Hibernate 级联保持 @OneToMany 与 @EmbeddedId 的关系【英文标题】:How do I cascade persist an @OneToMany relationship with an @EmbeddedId using Spring Data / Hibernate 【发布时间】:2021-12-27 12:35:17 【问题描述】:我已经看到很多类似的问题被问到这个问题,但还没有找到解决我看到的问题的解决方案,所以如果这是一个多余的问题,请提前道歉。在我的情况下,我有各种类型的实体,它们每个都有自己的标签关联。所以我想要一个通用的 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 又被 @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 on
parentId
没有任何效果,但我的语法可能已关闭。提前感谢任何知道如何解决此问题的人。
【问题讨论】:
【参考方案1】:对于任何想做类似事情的人,我终于找到了符合我标准的解决方案。
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 就足够了。
【讨论】:
以上是关于如何使用 Spring Data / Hibernate 级联保持 @OneToMany 与 @EmbeddedId 的关系的主要内容,如果未能解决你的问题,请参考以下文章
使用 Spring data mongo 和 Spring data elasticsearch 时如何建模?
如何将 @Transactional 与 Spring Data 一起使用?
“ java.lang.NoClassDefFoundError:javax / persistence / criteria / Selection”在JavaEE Maven项目中使用Hibern
使用 spring-data-jpa 获取这些数据如何更正确?
如何在 Spring Boot 应用程序的同一个域类上同时使用 Spring Data JPA 和 Spring Data Elasticsearch 存储库?