1

如何注释我的代码以拥有一个有 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 吗?我应该在这个注释上使用选项吗?

4

2 回答 2

1

不幸的是,这是不可能实现的@OneToOne。原因:

持久性提供程序将为表Person中的两个条目提供一个 id Address。这不足以决定给定的关系Address属于哪个关系。

最简单的解决方案是向实体添加一个type字段(枚举)并将地址映射到.Address@OneToMany/@ManyToOne

为了获得家庭住址,您需要遍历地址并检查类型。

或者,您可以创建额外的类型,例如HomeAddressandWorkAddress派生自Address. 然后您可以保留@OneToOne关系,但最终会得到两种额外的类型。

IMO 更清晰的实体关系映射并不是这样做的充分理由,因为您正在邀请一些问题。例如 aHomeAddress永远不能是 a WorkAddress

编辑:如果两个Addressid 都存储在Person表中,您应该能够使用该@OneToOne关系。为确保删除附加的地址实体和删除孤立的地址实体,您可以使用级联和孤立删除:

@OneToOne(cascade=CascadeType.ALL, orphanRemoval=true)

尽管看起来这样可以确保Address数据库中没有孤立记录,但这并不完全正确。仅当您在附加实体时删除事务中的引用实体时,孤儿删除才有效。此外,它不适用于批量更新。查询将DELETE FROM Person WHERE ...愉快地删除人员并且不会触及连接的地址。

于 2013-05-03T11:10:11.157 回答
0

OneToOne 意味着一个表具有另一个表的外键,但您没有指定哪个表,并且暗示这不是地址-> 人员的真正 1:1 情况。员工会有 workAddress_ID 和 homeAddress_id 字段吗?在这种情况下,有两个不同的 1:1。无效的是您的地址->员工 1:1,因为它无法同时使用 workAddress_ID 和 homeAddress_id 关系。您可以通过让地址具有 2 个私有的 OneToOnes 以及应用程序使用的公共 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;
            }
        }
    }
}
于 2013-05-03T13:42:25.190 回答