我在树和节点之间有多对多关系:
我在 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 指南,到目前为止我设法在数据库中保存树和节点,但现在中间表无法弄清楚我应该如何正确地注释字段(还有我应该如何注释树和节点也上课?),你能帮帮我吗?
我使用的指南:
您可以使用@MapsId; 也许这就是您想要实现的目标。
public class TreeNode {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer treeNodeId;
@ManyToOne
@MapsId("treeIdentifier")
private Tree tree;
@ManyToOne
@MapsId("nodeIdentifier")
private Node node;
}
我建议使用桥梁实体并在
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);
}
}
您可以使用
@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
实体。这避免了创建一个单独的连接实体来表示多对多关联。