Java JPA多态性单体瘤
我不知道如何使用JPA干净地创建一个标记云,其中每个db实体可以有许多标记 例如 Post可以有0个或多个标记 用户可以有0个或多个标记 在JPA中,有没有比让所有实体都子类化为Taggable抽象类更好的方法?其中标记实体将引用多个标记 编辑:标记云只是一个简化我遇到的问题的示例。在我的场景中,关系应该是OneToMany,其中标记不能重用Java JPA多态性单体瘤,java,jpa,polymorphism,Java,Jpa,Polymorphism,我不知道如何使用JPA干净地创建一个标记云,其中每个db实体可以有许多标记 例如 Post可以有0个或多个标记 用户可以有0个或多个标记 在JPA中,有没有比让所有实体都子类化为Taggable抽象类更好的方法?其中标记实体将引用多个标记 编辑:标记云只是一个简化我遇到的问题的示例。在我的场景中,关系应该是OneToMany,其中标记不能重用 谢谢为什么不映射一组标记甚至字符串呢 sudocode: @Entity @Table(name="entities") class MyEntity{
谢谢为什么不映射一组标记甚至字符串呢 sudocode:
@Entity
@Table(name="entities")
class MyEntity{
long id;
String someField;
@ManyToMany(targetEntity=Tag.class)
@JoinTable(name="entities_to_tags",
joinColumns={
@JoinColumn(name="id",
referencedColumnName="entity_id",
inverseJoinColumns={
@JoinColumn(name="id", referencedColumnName="tag_id")})
List<Tag> tags;
[...getter&setter...]
}
@Entity
@Table(name="tags")
class Tag{
@Id
@GeneratedValue
long id;
String title;
[....getter & setter...]
}
@实体
@表(name=“实体”)
类实体{
长id;
字符串字段;
@ManyToMany(targetEntity=Tag.class)
@JoinTable(name=“实体到标记”,
连接柱={
@JoinColumn(name=“id”,
referencedColumnName=“实体\u id”,
反向连接柱={
@JoinColumn(name=“id”,referencedColumnName=“tag\u id”)})
列出标签;
[…getter&setter…]
}
@实体
@表(name=“tags”)
类标签{
@身份证
@生成值
长id;
字符串标题;
[…..getter&setter…]
}
这似乎是多对多,而不是一对多。用户可以有多个标记,并且一个标记可以与多个用户关联
如果您想在标记上与包含每个标记对象的单个集合建立关系,则只需要这样一个超类。是否需要标记。GetOneGiantCollectionFeveryTaggedentity()
方法
由于标记的对象在其他方面似乎没有任何共同之处,这样的集合在您的应用程序域中真的有任何价值吗?它表面上也可能相当大,并且不是您真正希望通过对象关系处理的东西。从实际角度看,在不了解您的用例的情况下,它似乎像tag.getTaggedUsers()
,tag.getTaggedPosts()
等更有用
抱歉,我想我问的问题比回答的问题多,但不清楚您希望完成的对象域是什么样子:)
编辑:
也许问题的实际答案只是“不,Hibernate不会为您映射一个没有共同祖先的原始类型集合,这些类型碰巧都有实体的外键。”您不必在实体上强加一个“伪”超类,但如果不这样做,则必须创建一个联接表
.?如果您不需要多态查询,如“get everything tagged Foo”,那么您还可以引入一个新实体(比如
TaggingTarget
),并从用户创建一个单向一对一关系(Post
,等等)到标记目标
以及标记目标
和标记
之间的多对多关系:
@Entity
public class User {
@OneToOne
private TaggingTarget target;
...
}
@Entity
public class TaggingTarget {
@ManyToMany(...)
private Set<Tag> tags;
...
}
@Entity
public class Tag {
@ManyToMany(...)
private Set<TagTarget> targets;
...
}
或
在JPA中,有没有比让所有实体都子类化为Taggable抽象类更好的方法
让我们忘记这个例子:)JPA确实支持多态关联,但目标类必须是继承层次结构的一部分。下面是关于继承策略的一些经验法则:
- 单表:
- 层次结构中的所有类都映射到单个表
- 此策略提供了良好的支持,可以在
包含以下内容的实体和查询:
整个类层次结构
- 可能包含某些子类数据的空字段
- 每类表
- 层次结构中的每个类映射到一个单独的表,因此提供
对多态性的支持较差
关系
- 需要对每个子类进行SQL联合或单独的SQL查询
- 加入
- 无空字段=>压缩数据
- 这为多态关系提供了很好的支持,但是
需要一个或多个联接操作-
可能导致性能不佳
简而言之,如果您的子类声明的属性相对较少,则首选SINGLE_TABLE
策略。如果没有,则使用JOINED
策略,除非您具有较深的层次结构(在这种情况下,连接的成本可能会比联合的成本更高,然后TABLE_PER_CLASS
将“不那么糟糕”)
工具书类
- JPA1.0规范
- 第2.1.9节“继承”
- 第2.1.10节“2.1.10继承映射策略”
thx用于回复steve。在您的示例中,标签应包含一个“连接列”对于MyEntity,对吗?如果我有两个可标记的实体,例如MyEntity1和MyEntity2,那该怎么办?就像Aff一样,你可以使用@ManyToMany,这样你就可以得到一个从MyEntity的PKs到Tag的PK.thx的关系表来回复Aff。我给了Tag cloud作为示例来解决这个问题。对不起,这可能不是最好的示例。但理想情况下,我更喜欢OneToMany,因为在我的场景中,“标记”不被重用,我希望避免有额外的联接表。呵呵,我应该在编辑我的答案之前阅读您的评论,然后使用@manyToMany;)
select u from User u where :tag member of u.target.tags
select u from User u join u.target.tags t where t.name = :name