[英]Hibernate composite pattern with many-to-many composition
I want to create a tree structure where each node can have multiple parents and children.我想创建一个树结构,其中每个节点可以有多个父节点和子节点。 (So actually it is not really a tree but more of a network).
(所以实际上它不是真正的树,而是更多的网络)。
For example, we have an interface to implement the composition, a User
class which is the leaf node and a Group
class which builds the structure.例如,我们有一个接口来实现组合,一个
User
类是叶节点,一个Group
类构建结构。 There would be some check against recursion (adding a group to a group that had the first group as a parent somewhere).将对递归进行一些检查(将一个组添加到一个以第一组作为父级的组中)。
interface GroupMember {
boolean isLeaf();
}
class User implements GroupMember {
private int id;
private String name;
boolean isLeaf() { return true; }
}
class Group implements GroupMember {
private int id;
private Set<GroupMember> members;
boolean isLeaf() { return false; }
public addMember(GroupMember newMember) {
// Some check against recursion
members.add(newMember);
}
}
I see the most efficient way of implementing this in the database would be to have a link table (though this is just a suggestion and not required):我认为在数据库中实现这一点的最有效方法是拥有一个链接表(尽管这只是一个建议而不是必需的):
TABLE GROUP_MEMBER
-------------------
PARENT_ID NUMBER
CHILD_TYPE CHAR(1)
CHILD_ID NUMBER
However, I am not sure if Hibernate supports this design.但是,我不确定 Hibernate 是否支持这种设计。 It seems to me that in loading the
members
set in Group
Hibernate would have to consider the discriminator in the GROUP_MEMBER
table to decide which class to instantiate.在我看来,在加载
Group
Hibernate 中设置的members
,必须考虑GROUP_MEMBER
表中的GROUP_MEMBER
来决定要实例化哪个类。
I have considered having group containing two sets to separately fetch the groups and users, but this seems less than ideal.我曾考虑让包含两组的组分别获取组和用户,但这似乎不太理想。
May be I'm wrong, but I don't agree with having CHILD_TYPE to be part part of GROUP_MEMBER.可能是我错了,但我不同意让 CHILD_TYPE 成为 GROUP_MEMBER 的一部分。 I's a CHILD implementation detail and should stay with it.
我是一个孩子的实现细节,应该坚持下去。 By moving it to the CHILD table, you can use standard ManyToMany JPA mapping, which should make the life simpler.
通过将其移动到 CHILD 表,您可以使用标准的 ManyToMany JPA 映射,这应该会使事情变得更简单。
Entities:实体:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "CHILD_TYPE", length = 1)
@Table(name = "MEMBERS", schema = "mtm")
@Data //lombok
@EqualsAndHashCode(onlyExplicitlyIncluded = true) //lombok
public abstract class GroupMember {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@ManyToMany
@JoinTable(name = "GROUP_MEMBER", schema = "mtm",
joinColumns = @JoinColumn(name = "MEMBER_ID", referencedColumnName = "ID"),
inverseJoinColumns = @JoinColumn(name = "PARENT_ID", referencedColumnName = "ID"))
private Set<Group> parents = new HashSet<>();
public abstract boolean isLeaf();
}
@Entity
@DiscriminatorValue("G")
@Data
@EqualsAndHashCode(callSuper = true, onlyExplicitlyIncluded = true)
class Group extends GroupMember {
@ManyToMany(mappedBy = "parents")
private Set<GroupMember> members = new HashSet<>();
public boolean isLeaf() {
return false;
}
}
@Entity
@DiscriminatorValue("U")
@SecondaryTable(name = "USERS", schema = "mtm")
@Data
@EqualsAndHashCode(callSuper = true, onlyExplicitlyIncluded = true)
class User extends GroupMember {
@EqualsAndHashCode.Include
@Column(table = "USERS")
private String name;
public boolean isLeaf() {
return true;
}
}
Schema:架构:
create schema if not exists MTM;
CREATE TABLE MTM.MEMBERS (
id INT GENERATED BY DEFAULT AS IDENTITY,
CHILD_TYPE CHAR(1)
);
CREATE TABLE MTM.GROUP_MEMBER (
member_id INT,
parent_id INT
);
CREATE TABLE MTM.users (
id INT,
name varchar(255)
);
Notes:笔记:
@SecondaryTable
)@SecondaryTable
实现)isLeaf()
property.isLeaf()
属性引入一个额外的接口。I think you could use a @NamedQuery
looking like select g from Group g left join fetch g.members
on top of your Group
class and use this query with the Hibernate session.我认为您可以使用
@NamedQuery
看起来像select g from Group g left join fetch g.members
在您的Group
类之上,并在 Hibernate 会话中使用此查询。 Then you would use a query like select g from Group g left join fetch g.members where g.id = :id
and get the result then.然后你会使用像
select g from Group g left join fetch g.members where g.id = :id
这样的查询然后得到结果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.