【问题标题】:EclipseLink: multi-column, one-to-one, JPA 2.0 @EmbeddedId using @MapsId fails with read-only on @JoinColumn (derived identities compared)EclipseLink:多列,一对一,JPA 2.0 @EmbeddedId 使用 @MapsId 失败,@JoinColumn 上只读(比较派生身份)
【发布时间】:2011-08-25 18:03:51
【问题描述】:

我有以下设计:


(来源:kawoolutions.com

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

以下是 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注解,这两个注解都是用insertable = false, updatable = false定义的,表示嵌入的ID属性是可写的。

注意,我不是在寻找有效的解决方案,我可以简单地删除只读的 insertable = false, updatable = false 东西。然而,问题是 为什么 上述映射在 EclipseLink 中失败。 Hibernate 的代码没有问题。此外,使用 JPA 2.0 @IdClass 派生身份 的以下功能等效代码 - 在 EL 中没有问题工作,如下所示:

@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 然后“指向” writable PostAddressId 类,这与上面的@EmbeddedId 逻辑没有什么不同。至少逻辑对我来说没有什么不同。唯一的区别是,因为我使用的是@EmbeddedId,所以 writable @Column 注释最终在 @Embeddable 类中,这是有效的。 (JPA 只允许在 @Embeddable 类 @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 的只读属性,使用嵌套 ID 类 + EclipseLink 中的 @MapsId。

【问题讨论】:

    标签: hibernate jpa mapping jpa-2.0 eclipselink


    【解决方案1】:

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

    您是否有任何理由使用 mapsId 而不是仅将您的关系标记为 ID 然后使用 pk 类?

    【讨论】:

    猜你喜欢
    • 2012-09-27
    • 2014-10-21
    • 2020-08-20
    • 2011-08-24
    • 1970-01-01
    • 2013-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多