如何注释我的代码以拥有一个具有2个地址的人:
@Entity
public Person {
// ... other attributes for a person
@OneToOne
public Address homeAddress;
@OneToOne
public Address workAddress;
}
@Entity
public Address {
// ... other attributes for an address
@OneToOne
public Person person;
}
我可以使用OneToOne吗? 我是否应该在此注释上使用选项?
答案 0 :(得分:1)
不幸的是,@OneToOne
无法实现这一目标。原因是:
持久性提供程序将为Person
表的两个条目设置一个Address
id。这不足以决定给定Address
属于哪个关系。
最简单的解决方案是向type
实体添加Address
字段(枚举),并使用@OneToMany/@ManyToOne
映射地址。
为了获得家庭住址,您需要迭代地址并检查类型。
或者,您可以创建额外的类型,例如HomeAddress
和WorkAddress
,这些类型将派生自Address
。然后,您可以保持@OneToOne
关系,但最终会有两种类型。
IMO更清洁的实体关系映射不是充分理由,因为您正在邀请一些问题。例如,HomeAddress
永远不能是WorkAddress
。
编辑:如果两个Address
ID都存储在Person
表中,您应该可以使用@OneToOne
关系。要确保删除附加的地址实体和删除孤立的地址实体,您可以使用级联和孤立删除:
@OneToOne(cascade=CascadeType.ALL, orphanRemoval=true)
虽然看起来可能确保数据库中没有孤立的Address
记录,但这并不完全正确。只有在附加实体时删除事务内的引用实体时,孤立删除才有效。此外,它不适用于批量更新。 DELETE FROM Person WHERE ...
查询将很乐意删除人员,并且不会触及连接的地址。
答案 1 :(得分:0)
OneToOne意味着一个表有另一个外键,但你没有指定哪个,并且暗示它不是来自地址 - >人的真实1:1情况。员工是否有workAddress_ID和homeAddress_id字段?在这种情况下,有两种不同的1:1。无效的是您的地址 - >员工1:1,因为它无法同时使用workAddress_ID和homeAddress_id关系。您可以通过使地址具有2个私有的OneToOne来解决此问题,然后使用返回非空的应用程序的公共getPerson方法。设置这个人需要查看传入的人物对象,知道填写地址1:1中的哪一个,但由于他们无法控制关系,因此无关紧要:
public Address {
// ... other attributes for an address
@OneToOne(mappedby="workAddress")
private Person workPerson;
@OneToOne(mappedby="homeAddress")
private Person homePerson;
public Person getPerson() {
return workPerson==null? homePerson:workPerson;
}
public void setPerson(Person p) {
workPerson=null;
homePerson=null;
if (p !=null) {
if (p.getHomeAddress()==this) {
homePerson=p;
} else {
workPerson=p;
}
}
}
}