更新:我研究了一下,发现人们已经建立了一个关联实体来解决这类问题。这样做有一些限制,但最终结果看起来并不太糟糕。不过,可能还有一些我还没有想到的更好的设计方法。
Parent 实体将有一个OneToMany 映射到ParentChild 关联实体。必须设置mappedBy 属性以强制使用关联实体:
@Entity
public class Parent {
@Id @GeneratedValue private Long id;
@OneToMany(mappedBy="parent", cascade=CascadeType.ALL)
private List<ParentChild> children = new ArrayList<ParentChild>();
public void addChild(Child child, boolean teamLead) {
ParentChild association = new ParentChild();
association.setChild(child);
association.setParent(this);
association.setTeamLead(teamLead);
children.add(association);
child.setParent(this);
}
public Long getId() { return id; }
}
子实体将持有对父实体的引用,这与单向 ManyToMany 关系通常一样。
@Entity
public class Child {
@Id @GeneratedValue private Long id;
@ManyToOne
private Parent parent;
public Parent getParent() { return parent; }
public void setParent(Parent parent) { this.parent = parent; }
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
}
然后关联实体将具有对两个实体的ManyToOne 引用,以及一个主键。由于@MapsId 注释,关联引用使用与primary key 相同的id 字段。
@Entity
public class ParentChild {
@EmbeddedId
private ParentChildKey id;
@ManyToOne
@MapsId("parentId")
private Parent parent;
@ManyToOne
@MapsId("childId")
private Child child;
private boolean teamLead;
public ParentChild() { id = new ParentChildKey(); }
public boolean isTeamLead() { return teamLead; }
public void setTeamLead(boolean teamLead) { this.teamLead = teamLead; }
public Parent getParent() { return parent; }
public void setParent(Parent parent) { this.parent = parent; id.setParentId(parent.getId());}
public Child getChild() { return child; }
public void setChild(Child child) { this.child = child; id.setChildId(child.getId());}
}
主键实体没有什么特别之处。
@Embeddable
public class ParentChildKey implements Serializable {
private static final long serialVersionUID = 1L;
private Long parentId;
private Long childId;
public Long getParentId() { return parentId; }
public void setParentId(Long parentId) { this.parentId = parentId; }
public Long getChildId() { return childId; }
public void setChildId(Long childId) { this.childId = childId; }
... getters and setters
}
所以,它为我做了一个插入和选择,没有太多麻烦,但你可以看到它似乎只是为一个额外的字段做了大量的额外工作。当然,额外的字段(在本例中为teamLead)被有效地存储,但我可以想象一种“角色”类型的配置,从长远来看会更容易使用并且更有意义。