【发布时间】:2017-08-05 03:03:30
【问题描述】:
我的数据库中有两个表,它们通过复合主键/外键映射在一起,而且我在让 Hibernate 与它们一起工作时遇到了很多麻烦。我的数据库如下所示:
TABLE1 有一个由外键组成的复合主键,映射到 TABLE_A 和 TABLE_B。 TABLE2 还具有外键的复合主键,映射到 TABLE_A、TABLE_B 和 TABLE_D。在数据库中,TABLE2 仅使用前两个外键映射回 TABLE1。那里没有问题。它正在将其转换为 Hibernate,这正在杀死我。
因为 TABLE2 需要一个包含三列的嵌入式 id,所以我不能使用 @OneToMany 注释的 mappedBy 参数。我得到与主键列不匹配的外键数量的预期错误。所以,我改用@JoinColumns。这对于保存新实体非常有效。但是,当我尝试从 TABLE2 中删除一些映射时,我遇到了一个问题,即 Hibernate 在删除之前尝试更新 TABLE2,将 FK_TABLE_A 设置为 null,这显然是不允许的。我能找到的最好的方法是在映射 xml 中使用 inverse="true" 可能会解决问题,确保 Hibernate 知道尽管使用了@JoinColumn,但 TABLE1 实体应该是关系的所有者.但我没有使用 XML,我无法通过注释弄清楚等价物是什么。
这是我目前所拥有的:
@Entity
@AssociationOverrides({
@AssociationOverride(name = "pk.tableA",
joinColumns = @JoinColumn(name = "FK_TABLE_A")),
@AssociationOverride(name = "pk.tableB",
joinColumns = @JoinColumn(name = "FK_TABLE_B")) })
@Table(name="TABLE1")
public class Table1 extends BaseObject implements Serializable
{
private static final long serialVersionUID = 1L;
private Table1Id pk = new Table1Id();
@EmbeddedId
public Table1Id getPk() {
return pk;
}
public void setPk(Table1Id pk) {
this.pk = pk;
}
private TableC tableC;
@ManyToOne
@JoinColumn(name = "FK_TABLE_C", referencedColumnName = "ID", nullable = true)
public TableC getTableC () {
return this.tableC;
}
public void setTableC(TableC tableC) {
this.tableC= tableC;
}
private List<Table2> table2s;
@OneToMany(cascade = {CascadeType.ALL}, orphanRemoval=true, fetch=FetchType.EAGER)
@JoinColumns({
@JoinColumn(name="FK_TABLE_A", referencedColumnName="FK_TABLE_A"),
@JoinColumn(name="FK_TABLE_B", referencedColumnName="FK_TABLE_B")
})
public List<Table2> getTable2s() {
return table2s;
}
public void setTable2s(List<Table2> table2s) {
this.table2s= table2s;
}
@Override
public boolean equals(Object o) {
...
}
@Override
public int hashCode() {
...
}
@Override
public String toString() {
...
}
}
@Embeddable
public class Table1Id extends BaseObject implements Serializable
{
private static final long serialVersionUID = 1L;
private TableA tableA;
private TableB tableB;
@ManyToOne
public TableA getTableA() {
return tableA;
}
public void setTableA(TableA tableA) {
this.tableA = tableA;
}
@ManyToOne
public TableB getTableB() {
return tableB;
}
public void setTableB(TableB tableB) {
this.tableB= tableB;
}
@Override
public boolean equals(Object o) {
...
}
@Override
public int hashCode() {
...
}
@Override
public String toString() {
...
}
}
@Entity
@AssociationOverrides({
@AssociationOverride(name = "pk.tableA",
joinColumns = @JoinColumn(name = "FK_TABLE_A")),
@AssociationOverride(name = "pk.tableB",
joinColumns = @JoinColumn(name = "FK_TABLE_B")),
@AssociationOverride(name = "pk.tableD",
joinColumns = @JoinColumn(name = "FK_TABLE_D")) })
@Table(name="TABLE2")
public class Table2 extends BaseObject implements Serializable
{
private static final long serialVersionUID = 1L;
private Table2Id pk = new Table2Id ();
@EmbeddedId
public Table2Id getPk() {
return pk;
}
public void setPk(Table2Id pk) {
this.pk = pk;
}
private Double value;
@Column(name = "VALUE", nullable = false, insertable = true, updatable = true, precision = 2)
@Basic
public Double getValue() {
return this.value;
}
public void setValue(Double value) {
this.goal = goal;
}
@Override
public boolean equals(Object o) {
...
}
@Override
public int hashCode() {
...
}
@Override
public String toString() {
...
}
}
@Embeddable
public class Table2Id extends BaseObject implements Serializable
{
private static final long serialVersionUID = 1L;
private TableA tableA;
@ManyToOne
public TableA getTableA() {
return tableA;
}
public void setTableA(TableA tableA) {
this.tableA= tableA;
}
private TableB tableB;
@ManyToOne
public TableB getTableB() {
return tableB;
}
public void setTableB(TableB tableB) {
this.tableB= tableB;
}
private TableD tableD;
@ManyToOne
public TableD getTableD() {
return this.tableD;
}
public void setTableD(TableD tableD) {
this.tableD= tableD;
}
@Override
public boolean equals(Object o) {
...
}
@Override
public int hashCode() {
...
}
@Override
public String toString() {
...
}
}
通常对于这样的关系,我只使用 @OneToMany 注释的 mappedBy 值,一切正常 - 更新、插入和删除按预期和期望执行。但是考虑到基础表的构造方式公认的奇怪,我不能这样做。仅映射到 Table2Id 中的单个记录(mappedBy="pk.tableA" 或 mappedBy="pk.tableB")将导致完全不正确的数据。我要求两个字段都有适当的匹配,但据我所知,我不能在 mappedBy 中列出多个列。 mappedBy="pk.tableA, pk.tableB" 失败。
我知道我可以很容易地解决这个问题,只需修改数据库并将单个 ID 主键添加到 TABLE1,并将单个 FK_TABLE1 主键添加到 TABLE2。然后我可以使用我的标准方法@OneToMany(mappedBy="table1"...)。但我真的希望避免这种情况,如果没有其他原因,我显然不需要在数据库级别这样做。我希望有一种方法可以告诉 Hibernate Table1 是所有者,并且对 Table2 的所有更改都依赖于它。
【问题讨论】: