我有以下设计:
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。
答案 0 :(得分:4)
EclipseLink将mapsId解释为表示关系控制Foos表中定义的contact_id和ordinal_nbr列。因此,当您将关系字段标记为只读时,这意味着这些字段没有可写映射 - mapsId告诉提供程序需要从关系中使用这些值,但该关系是只读的。
你有没有理由使用mapsId而不是仅仅将你的关系标记为ID然后使用pk类?