假设我们有四个实体A,B,C和Document。
A -> Many Documents (one-to-many)
B -> Many Documents (one-to-many)
C -> Many Documents (one-to-many)
A,B,C可以有很多文件。 在传统的一对多映射样式中,我们将具有如下的Document表:
如果我添加A实体的文档,那么对于这些文档,B_id和C_id将为null。 B和C的文件也一样。 希望问题很清楚。
我希望Document实体只保留一个id和实体类,我可以用hibernate方式查询Document表。
或任何其他解决问题的方法。
答案 0 :(得分:1)
Thorben Jansssen撰写了一篇很棒的博客文章。
https://www.thoughts-on-java.org/complete-guide-inheritance-strategies-jpa-hibernate/
对于您的情况,单表策略可能是合适的。如果你不想a_id,b_id,c_id将为null,你可以用2列替换它们:
| doc_id | doc_field_1 | doc_field_2 |类型| ENTITY_ID |
和实体映射如下:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type")
@Table(name = "document")
public abstract class Document {
// ...
}
@Entity
@DiscriminatorValue(value = "A")
public class DocumentOfTypeA extends Document{
...
@ManyToOne
@Column(name="entity_id")
A aEntity;
}
和您的实体类:
// A.java
public class A{
// ...
// @OneToMany (...)
private Set<DocumentOfTypeA> documents;
}
与B和C实体相同。
答案 1 :(得分:0)
请注意,每个对象A,B,C在其表中也都有一个ID字段。在大多数情况下,这些都是由数据库使用序列生成器生成的:
@SequenceGenerator(name = "seqA", sequenceName = "seqA_gen")
@Entity
public class A {
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seqA")
@Id
private Long Id
@OneToMany (...)
private Set<Document> documents;
}
A类的Id值可以与B或C类相同。如果您使用单个表存储所有三个类的Document行,通常情况下,您必须使用除确定哪些行属于对象的ID。可以通过显示的多个ID列来完成此操作,也可以使用一个ID列和一个鉴别符列来完成此操作,本质上说“此ID适用于A类”
所以这是另一种方法:所有三个类仅使用一个ID序列生成器。
这可以通过简单地对所有三个类使用相同的sequenceName来完成。
@SequenceGenerator(name = "seqA", sequenceName = "shared_gen")
@SequenceGenerator(name = "seqB", sequenceName = "shared_gen")
@SequenceGenerator(name = "seqC", sequenceName = "shared_gen")
如果使用相同的序列生成器,则ID永远不会重叠,并且您可以使用文档表中的单个列为所有父类链接@onetomany。决不存在通过ID进行查询的查询返回其他父对象的数据的情况。
可能更常见的第二种方法是使用随机UUID 作为A,B和C类的ID生成器。ID占用更多内存,但提供了统计上完全的隔离。
这两种方法使得可以将包括一组文档的任何数量的新类添加到应用程序中,而无需修改“文档”表中的列或要求开发人员跟踪判别值。