我有两张桌子 -
Foo {foo_id,name}
Foo_properties {fp_id,foo_id,phoneNumber}
现在我想使用hibernate在我的对象模型中映射它。
我需要在Foo_properties中使用foo_id,因为我想保持参照完整性并希望添加ON DELETE CASCADE约束。
所以我按照以下方式绘制了关系 -
@Entity
public class Foo{
@Id
private long foo_id;
private String name;
@OneToOne(mappedBy = "foo")
private FooProperties fooProperties;
}
@Entity
public class FooProperties{
@Id
private long fp_id;
private String phoneNumber;
@OneToOne
@JoinColumn(name = "foo_id", nullable = false)
private Foo foo;
}
既然拥有方是FooProperties类,我面临以下问题 -
如果我将FooProperties的新实例设置为Foo,则现有的FooProperties仍然保留在DB中,而hibernate不会删除该实例,例如
Foo foo = entityManager.find(Foo.class, fooId);
foo.setFooProperties(new FooProperties("xxx-xxx-xxx"));
entityManager.merge(foo);
这导致FooProperties表中的新行以及现有行。现在我不明白我如何改变我的映射,所以我可以让上面的代码(或它的变体)适用于所有场景,这意味着我需要Foo作为拥有方和FooProperties中的foo_id。有没有办法像这样定义映射?
注意:我已基于此问过question,但我认为我在上一个问题中并不清楚,所以又问了另一个问题。
答案 0 :(得分:4)
您已被告知使用orphanRemoval = true
或CascadeType.DELETE_ORPHAN
。但是,由于对JPA规范的解释具有欺骗性,因此对于一对一的关系(HHH-5559),它将无法正常工作。
您可以使用以下技巧实现orphanRemoval
的正确行为:
@Entity
public class Foo{
@OneToMany(mappedBy = "foo", orphanRemoval = true)
private List<FooProperties> fooProperties;
public FooProperties getFooProperties() {
if (fooProperties == null || fooProperties.isEmpty()) return null;
else return fooProperties.get(0);
}
public void setFooProperties(FooProperties newFooProperties) {
if (fooProperties == null) fooProperties = new ArrayList<FooProperties>();
else fooProperties.clear();
if (newFooProperties != null)
fooProperties.add(newFooProperties);
}
...
}
@Entity
public class FooProperties{
@ManyToOne
@JoinColumn(name = "foo_id", nullable = false)
private Foo foo;
...
}
如果您不需要FooPropeties.foo
:
@Entity
public class Foo{
@OneToMany(orphanRemoval = true)
@JoinColumn(name = "foo_id", nullable = false)
private List<FooProperties> fooProperties;
// getter/setter as above
...
}
答案 1 :(得分:2)
我认为不是在实体上调用merge,如果直接调用更新会话对象,那么hibernate将首先删除现有行,然后添加新行。我实现了相同的,但在我的情况下,我使用xml映射实体。我希望这会对你有所帮助。
答案 2 :(得分:0)
答案 3 :(得分:0)
有两个选项供您选择,因为您不想更改映射: