创建多对多关系的两个表中的多对多复合键如何注释它们

问题描述 投票:0回答:3

我在树和节点之间有多对多关系:

  • 树可以有很多节点。
  • 节点可以在许多树中。

我在 Tree 表和 Node 表中也有复合主键。

所以我的模型类看起来像这样:

@Entity
@Table(name = "tree")
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class Tree {
    @EmbeddedId
    private TreeIdentifier treeIdentifier;
    private LocalDateTime creationDate;
}

TreeIdentifier(这是树的主键):

@Embeddable
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class TreeIdentifier implements Serializable {

    private String treeId;
    private String siteId;
    private Integer prodVersion;

    @Override
    public int hashCode() {
        return Objects.hash(prodVersion, siteId, treeId);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        TreeIdentifier other = (TreeIdentifier) obj;
        return Objects.equals(prodVersion, other.prodVersion) && Objects.equals(siteId, other.siteId)
                && Objects.equals(treeId, other.treeId);
    }

    private static final long serialVersionUID = 1L;
}

节点:

@Entity
@Table(name = "node")
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) 
public class Node {
    @EmbeddedId
    private NodeIdentifier nodeIdentifier;
    private Long nodePosition;
}

NodeIdentifier(节点的主键):

@Embeddable
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class NodeIdentifier implements Serializable {

    private String nodeId;
    private Integer nodeVersionId;

    @Override
    public int hashCode() {
        return Objects.hash(nodeId, nodeVersionId);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        NodeIdentifier other = (NodeIdentifier) obj;
        return Objects.equals(nodeId, other.nodeId) && Objects.equals(nodeVersionId, other.nodeVersionId);
    }

    private static final long serialVersionUID = 1L;

}

现在我正在努力弄清楚由于这种 ManyToMany 关系而激增的中间表在代码中应该是什么样子:

树节点

@Entity
@Table(name = "tree_node")
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class TreeNode {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer treeNodeId;
    private Tree tree;
    private Node node;
}

我一直在关注 Baeldung 指南,到目前为止我设法在数据库中保存树和节点,但现在中间表无法弄清楚我应该如何正确地注释字段(还有我应该如何注释树和节点也上课?),你能帮帮我吗?

我使用的指南:

java jpa spring-data-jpa many-to-many
3个回答
1
投票

您可以使用@MapsId; 也许这就是您想要实现的目标。

public class TreeNode {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer treeNodeId;
    @ManyToOne
    @MapsId("treeIdentifier")
    private Tree tree;
    @ManyToOne
    @MapsId("nodeIdentifier")
    private Node node;

}

1
投票

我建议使用桥梁实体并在

one-to-many
many-to-one
Tree
实体之间创建
TreeNode
Node
关系,如下所示:

树:

@Entity
public class Tree {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // other fields, getter/setter, constructors, equals and hashCode methods ...

    @OneToMany(mappedBy = "tree", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<TreeNode> treeNodes = new ArrayList<>();

    public void addTreeNode(TreeNode treeNode) {
        treeNodes.add(treeNode);
        treeNode.setTree(this);
    }

    public void removeTreeNode(TreeNode treeNode) {
        treeNodes.remove(treeNode);
        treeNode.setTree(null);
    }
}

树节点:

@Entity
public class TreeNode {

    @EmbeddedId
    private TreeNodeId treeNodeId = new TreeNodeId();

    // other fields, getter/setter, constructors, equals and hashCode methods ...

    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("treeId")
    @JoinColumn(name = "tree_id", referencedColumnName = "id")
    private Tree tree;

    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("nodeId")
    @JoinColumn(name = "node_id", referencedColumnName = "id")
    private Node node;
}

TreeNodeId:

@Embeddable
public class TreeNodeId implements Serializable {

    @Column(name = "tree_id", nullable = false)
    private Long treeId;

    @Column(name = "node_id", nullable = false)
    private Long nodeId;

    // getter/setter, equals and hashCode methods ...
}

节点:

@Entity
public class Node {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // other fields, getter/setter, constructors, equals and hashCode methods ...

    @OneToMany(mappedBy = "node", cascade = CascadeType.ALL)
    private Set<TreeNode> treeNodes = new HashSet<>();

    public void addTreeNode(TreeNode treeNode) {
        treeNodes.add(treeNode);
        treeNode.setNode(this);
    }

    public void removeTreeNode(TreeNode treeNode) {
        treeNodes.remove(treeNode);
        treeNode.setNode(null);
    }
}

0
投票

您可以使用

@ManyToMany
注解在
Tree
Node
实体之间建立多对多关系,而无需使用桥接实体:

树:

@Entity
@Table(name = "tree")
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class Tree {
    @EmbeddedId
    private TreeIdentifier treeIdentifier;
    private LocalDateTime creationDate;

    @ManyToMany
    @JoinTable(
            name = "tree_node",
            joinColumns = @JoinColumn(name = "tree_id"),
            inverseJoinColumns = @JoinColumn(name = "node_id")
    )
    private List<Node> nodes;
}

节点:

@Entity
@Table(name = "node")
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) 
public class Node {
    @EmbeddedId
    private NodeIdentifier nodeIdentifier;
    private Long nodePosition;

    @ManyToMany(mappedBy = "nodes")
    private List<Tree> trees;
}

Tree
类中,一个
@ManyToMany
注解来定义与
Node
类的多对多关系。指定
@JoinTable
注释以定义连接表名称和将
Tree
实体链接到连接表的连接列。
inverseJoinColumns
属性指定将
Node
实体链接到连接表的连接列。

Node
类中,带有
@ManyToMany
属性的
mappedBy
注释告诉
JPA
nodes
字段是关系的反面,拥有方是
Tree
实体。这避免了创建一个单独的连接实体来表示多对多关联。

© www.soinside.com 2019 - 2024. All rights reserved.