我的数据库中有两个表通过复合主键/外键映射在一起,而且我有一段时间让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,这显然是不允许的。我能找到的最好的是使用inverse =" true"在映射xml中可能会解决问题,确保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 =&#34; pk.tableA&#34;或mappedBy =&#34; pk.tableB&#34;)将导致完全不正确的数据。我要求两个字段都有适当的匹配,但我可以告诉我不能在mappedBy中列出多个列。 mappedBy =&#34; pk.tableA,pk.tableB&#34;失败。
我知道只需修改数据库并向TABLE1添加单个ID主键,并向TABLE2添加单个FK_TABLE1主键,即可轻松解决此问题。然后我可以使用@OneToMany的标准方法(mappedBy =&#34; table1&#34; ...)。但我真的希望避免这种情况,如果没有其他原因我显然不需要在数据库级别上这样做。我希望有一种方法告诉Hibernate Table1是所有者,并且对Table2的所有更改都依赖于它。
答案 0 :(得分:0)
问题在于Table2嵌入式Id直接映射到与Table1嵌入式Id相同的实体。这就是我想要的数据库,但不是我想要的Hibernate。相反,TableA和TableB的两个字段应该由Table1本身表示,并且关联覆盖写入匹配。它们需要包含insertable = false和updatable = false,以便Table2不能对Table1进行任何更改。就我而言,我只想要一个单向的关系。然后,Table1可以使用@OneToMany批注的mappedBy参数直接映射到自身。这允许Table1控制关系。所以,代码应该是:
@Entity
@AssociationOverrides({
@AssociationOverride(name = "pk.tableA",
joinColumns = @JoinColumn(name = "FK_TABLE_A", nullable=false)),
@AssociationOverride(name = "pk.tableB",
joinColumns = @JoinColumn(name = "FK_TABLE_B", nullable=false)) })
@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(mappedBy="pk.table1", cascade = {CascadeType.ALL}, orphanRemoval=true, fetch=FetchType.EAGER)
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() {
...
}
}
@Entity
@AssociationOverrides({
@AssociationOverride(name = "pk.table1",
joinColumns = {
@JoinColumn(name = "FK_TABLE_A", nullable=false, insertable=false, updatable=false),
@JoinColumn(name = "FK_TABLE_B", nullable=false, insertable=false, updatable=false)
}),
@AssociationOverride(name = "pk.tableD",
joinColumns = @JoinColumn(name = "FK_TABLE_D", nullable=false)) })
@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.value = value;
}
@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 Table1 table1;
@ManyToOne
@JoinColumn(nullable=false)
public Table1 getTable1() {
return this.table1;
}
public void setTable1(Table1 table1) {
this.table1 = table1;
}
private TableD tableD;
@ManyToOne
@JoinColumn(nullable=false)
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() {
...
}
}