复合主键,外键。引用对象或密钥?

时间:2012-06-09 12:08:32

标签: java jpa composite-key

我有两个班级FooBar。数据库中的表格如下所示:

|Foo|
|id : INT (PK) | bar_id : INT (PK, FK) |

|Bar|
|id : INT (PK) |

通常我会像这样映射:

@Entity
public class Bar
{
    @Id
    @Column(name = "id")
    private int id;

    @OneToMany
    private Set<Foo> foo;
}

@Entity
public class Foo
{
    @EmbeddedId
    private FooPK key;

    @MapsId("barId")
    @ManyToOne
    @JoinColumn(name = "bar_id", referencedColumnName = "id")
    private Bar bar;
}

@Embeddable
public class FooPK
{
    @Column(name = "id")
    private int id;
    @Column(name = "bar_id")
    private int barId;
}

然而,FooPK中的ID被松散地映射,需要手动连接。我更喜欢使用Objects映射而不是松散ID的解决方案。 我尝试了以下但是(当然)它不起作用,但我认为它给出了我想要实现的目标:

@Entity
public class Bar
{
    @Id
    @Column(name = "id")
    private int id;

    @OneToMany
    private Set<Foo> foo;
}

@Entity
public class Foo
{
    @EmbeddedId
    private FooPK key;

    @MapsId("barId")
    @ManyToOne
    @JoinColumn(name = "bar_id", referencedColumnName = "id")
    @Access(AccessType.FIELD)
    private Bar getBar()
    {
        return key.getBar();
    }
}

@Embeddable
public class FooPK
{
    @Column(name = "id")
    private int id;

    @Transient
    private Bar bar;

    //....

    @Column(name = "bar_id")
    @Access(AccessType.PROPERTY)
    private int getBarId
    {
        return bar.getId();
    }
}

后一种解决方案的另一个问题是getBarId()中的FooPK方法需要setBarId(Int)方法。使用ID设置对象可以通过访问数据访问层来完成,但是(在我看来)这违反了业务/域/数据层的分离。

那该怎么办?使用第一个解决方案并手动保持ID同步或是否有其他(最佳)练习?

1 个答案:

答案 0 :(得分:23)

参考JPA 2: composite primary key classes讨论,对Foo和FooPK类进行以下更改:

@Entity
public class Foo {

    @EmbeddedId
    private FooPK key;

    @MapsId("barId") //references EmbeddedId's property
    @JoinColumn(name = "bar_id", referencedColumnName = "id")
    @ManyToOne
    private Bar bar;
}

@Embeddable
public class FooPK {

    @Column(name = "id")
    private int id;
    @Column(name = "bar_id")
    private int barId;
}

我建议首先使用FIELD访问权限,然后应用PROPERTY访问权限。

  

那该怎么办?使用第一个解决方案并保持ID同步   手动还是有其他(最佳)练习?

免于痛苦 - 自动生成ID。