EclipseLink:多列,一对一,JPA 2.0 @EmbeddedId使用@MapsId失败,只读@JoinColumn(派生身份比较)

时间:2011-05-15 02:16:55

标签: hibernate jpa mapping jpa-2.0 eclipselink

我有以下设计:

Valid XHTML http://kawoolutions.com/media/nontransmuc-onetoone.png

简单逻辑:Foos使用相同列(相同的键)对PostAddresses使用多列PK。

以下是 JPA 2.0 @EmbeddedId 映射(使用FooId中的嵌套ID类PostAddressId和Foo中的@MapsId注释映射到它):

@Entity
@Table(name = "PostAddresses")
public class PostAddress implements Serializable
{
    @EmbeddedId
    private PostAddressId embeddedId;

    ...
}

@Embeddable
public class PostAddressId implements Serializable
{
    @Column(name = "contact_id")
    private Integer contactId;

    @Column(name = "ordinal_nbr")
    private Integer ordinalNbr = 1;

    ...
}

@Entity
@Table(name = "Foos")
public class Foo implements Serializable
{
    @EmbeddedId
    private FooId embeddedId;

    @MapsId(value = "postAddressId")
    @OneToOne
    @JoinColumns(value = {
        @JoinColumn(name = "contact_id", referencedColumnName = "contact_id", insertable = false, updatable = false),
        @JoinColumn(name = "ordinal_nbr", referencedColumnName = "ordinal_nbr", insertable = false, updatable = false)
    })
    private PostAddress postAddress;

    ...
}

@Embeddable
public class FooId implements Serializable
{
    @Embedded
    private PostAddressId postAddressId;

    ...
}

堆栈追踪:

Exception [EclipseLink-46] (Eclipse Persistence Services - 2.3.0.v20110429-r9282): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: There should be one non-read-only mapping defined for the primary key field [Foos.ordinal_nbr].
Descriptor: RelationalDescriptor(tld.transmuc.model.Foo --> [DatabaseTable(Foos)])

Runtime Exceptions:
---------------------------------------------------------

    at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.initializeDescriptors(DatabaseSessionImpl.java:535)
    at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.initializeDescriptors(DatabaseSessionImpl.java:476)
    at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.initializeDescriptors(DatabaseSessionImpl.java:435)
    at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.postConnectDatasource(DatabaseSessionImpl.java:673)
    at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.loginAndDetectDatasource(DatabaseSessionImpl.java:618)
    at org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.login(EntityManagerFactoryProvider.java:206)
    at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:460)
    ... 4 more

对我来说,映射是正确的。我多次检查过它们。注意,在FooId中使用@Embedded注释是否与EL没有区别。

请注意其中两个用定义Foo.postAddress关系的@JoinColumn注解插入=假,可更新=假以指示所述嵌入式ID属性是可写的。

注意,我不是在找一个有效的解决方案,我只能删除只读 insertable = false,updatable = false 的东西。然而,问题是为什么以上映射在EclipseLink中失败。 Hibernate对代码有没问题。此外,以下功能相当的代码 - 在EL中使用没有问题 - 使用 JPA 2.0 @IdClass派生身份看起来像:

@Entity
@Table(name = "PostAddresses")
@IdClass(value = PostAddressId.class)
public class PostAddress implements Serializable
{
    @Id
    @Column(name = "contact_id")
    private Integer contactId;

    @Id
    @Column(name = "ordinal_nbr")
    private Integer ordinalNbr = 1;

    ...
}

public class PostAddressId implements Serializable
{
    private Integer contactId;

    private Integer ordinalNbr = 1;

    ...
}

@Entity
@Table(name = "Foos")
@IdClass(value = FooId.class)
public class Foo implements Serializable
{
    @Id
    @OneToOne
    @JoinColumns(value = {
        @JoinColumn(name = "contact_id", referencedColumnName = "contact_id", insertable = false, updatable = false),
        @JoinColumn(name = "ordinal_nbr", referencedColumnName = "ordinal_nbr", insertable = false, updatable = false)
    })
    private PostAddress postAddress;

    ...
}

public class FooId implements Serializable
{
    private PostAddressId postAddress;

    ...
}

如您所见,Foo.postAddress还包含只读 insertable = false,updatable = false 属性。 Foo.postAddress通过命名它们来映射到FooId.postAddress。 FooId然后“指向”可写 PostAddressId类,这与上面的@EmbeddedId逻辑没有什么不同。至少逻辑与我没有什么不同。唯一的区别是,因为我正在使用@EmbeddedId,可写的@Column 注释最终会出现在@Embeddable类中,这是有效的。 (JPA只允许@Embeddeddable类@Embedded,@ Basic,@ Column,@ Temporal,@ Enum和@Binary AFAIK中的简单注释。)

有什么我想念的吗? JPA 2.0规范在这里说的是什么?

或者这是EclipseLink中的错误吗?

最后说明:这个问题显然与JPA (Hibernate, EclipseLink) mapping: why doesn't this code work (chain of 2 relationships using JPA 2.0, @EmbeddedId composite PK-FK)?类似,但不一样。在此期间,链接问题的EL已得到修复,我正在使用固定版本的EL,因此问题不一样。这个仅仅是关于JPA 2.0 @EmbeddedId中@JoinColumn的只读属性,它使用EclipseLink中的嵌套ID类+ @MapsId。

1 个答案:

答案 0 :(得分:4)

EclipseLink将mapsId解释为表示关系控制Foos表中定义的contact_id和ordinal_nbr列。因此,当您将关系字段标记为只读时,这意味着这些字段没有可写映射 - mapsId告诉提供程序需要从关系中使用这些值,但该关系是只读的。

你有没有理由使用mapsId而不是仅仅将你的关系标记为ID然后使用pk类?