相同类型的JPA @OneToOne

时间:2013-05-03 10:33:15

标签: java jpa one-to-one

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

2 个答案:

答案 0 :(得分:1)

不幸的是,@OneToOne无法实现这一目标。原因是:

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

最简单的解决方案是向type实体添加Address字段(枚举),并使用@OneToMany/@ManyToOne映射地址。

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

或者,您可以创建额外的类型,例如HomeAddressWorkAddress,这些类型将派生自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;
            }
        }
    }
}