java - 具有多对多组合的 Hibernate 组合模式

标签 java hibernate many-to-many composite

我想创建一个树结构,其中每个节点可以有多个父节点和子节点。 (所以实际上它不是一棵树,而更像是一个网络)。

例如,我们有一个实现组合的接口(interface),一个作为叶节点的User类和一个构建结构的Group类。将对递归进行一些检查(将一个组添加到一个组中,该组在某处将第一个组作为父组)。

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);
    }
}

我看到在数据库中实现它的最有效方法是有一个链接表(虽然这只是一个建议,并不是必需的):

TABLE GROUP_MEMBER
-------------------
PARENT_ID    NUMBER
CHILD_TYPE   CHAR(1)
CHILD_ID     NUMBER

不过,我不确定Hibernate是否支持这种设计。在我看来,在加载 Group 中的 members 集时,Hibernate 必须考虑 GROUP_MEMBER 表中的鉴别器来决定实例化哪个类.

我考虑过让组包含两个集合来分别获取组和用户,但这似乎不太理想。

最佳答案

可能我错了,但我不同意让 CHILD_TYPE 成为 GROUP_MEMBER 的一部分。我是 CHILD 实现细节,应该保留它。通过将其移动到 CHILD 表,您可以使用标准的 ManyToMany JPA 映射,这应该会使生活更简单。

  • 如果需要,CHILD_TYPE 可以是 CHILD 表内的鉴别器。
  • 我总是建议有一个 FK。错误时有发生,数据库中的孤儿总是令人头疼。

实体:

@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;
    }

}

架构:

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)
);

注意事项:

  • 实现标准 Hibernate MTM 和继承策略
  • 公共(public)数据存储在 MEMBERS 表中,用户特定的数据存储在 USERS 表中(使用 @SecondaryTable 实现)
  • Group 数据完全存储在 MEMBERS 中以提高效率(消除 JOIN),但可以像 User 一样扩展
  • 如果需要,可以为 isLeaf() 属性引入一个额外的接口(interface)。

关于java - 具有多对多组合的 Hibernate 组合模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57373253/

相关文章:

java - 安装后如何将应用程序注册为启动器

java - Web服务客户端,我应该保留服务还是端口实例?

java - 如何在 camera2 API 中触发手动自动对焦?

python - Django/mysql中间表不插入数据

javascript - 如何使用 Adonis 中的用户角色更新联结表

java - ReplaceChild() 时 org.w3c.dom.DOMException 没有详细消息

Hibernate java.lang.ClassCastException : org. hibernate.action.EntityIdentityInsertAction 无法转换为 org.hibernate.action.EntityInsertAction

java - 使用外键对 2 个表进行关联时出现 Criteria 问题

java - Dao实现中如何进行以下操作?

Laravel 定义同一张表的多对多关系