У меня есть следующий дизайн:
Действительный XHTML http://kawoolutions.com/media/nontransmuc-onetoone.png
Простая логика: Foos использует многоколоночный PK для PostAddresses, используя те же столбцы (тот же ключ).
Вот сопоставления JPA 2.0 @ EmbeddedId (с использованием вложенного идентификатора класса PostAddressId в FooId и аннотации @MapsId в Foo для сопоставления с ним):
@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
Для меня отображения верны. Я проверил их несколько раз. Обратите внимание, что использование аннотации @Embedded в FooId или нет не имеет значения в EL.
Обратите внимание на аннотации @JoinColumn отношений Foo.postAddress, которые оба были определены с помощью inserttable = false, updatable = false , чтобы указать, что встроенные свойства ID должны быть записываемыми.
Обратите внимание, я не ищу решение, которое работает, я могу получить это, просто удаляя доступный только для чтения inserttable = 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 также содержит атрибуты только для чтения inserttable = false, updatable = false . Foo.postAddress сопоставляется с FooId.postAddress, называя их одинаковыми. Затем FooId «указывает» на класс доступный для записи PostAddressId, который ничем не отличается от логики @EmbeddedId выше. По крайней мере, логика не отличается от меня. Единственное отличие состоит в том, что я использую @EmbeddedId, что аннотации writable @ Column заканчиваются в классе @Embeddable, который является допустимым. (JPA допускает только простые аннотации в классах @Embeddable @Embedded, @Basic, @Column, @Temporal, @Enum и @Binary AFAIK.)
Есть что-то, что я пропускаю? Что здесь говорится в спецификации JPA 2.0?
Или это ошибка в EclipseLink?
Заключительное примечание: этот вопрос, очевидно, аналогичен JPA (Hibernate, EclipseLink) отображению: почему этот код не работает (цепочка из двух отношений, использующих JPA 2.0, @EmbeddedId композитный PK-FK)? но не то же самое. Тем временем EL связанного вопроса был исправлен, и я использую эту исправленную версию EL, поэтому проблемы не совпадают. Этот раздел предназначен исключительно для атрибутов только для чтения в @JoinColumn в JPA 2.0 @EmbeddedId с использованием вложенных классов ID + @MapsId в EclipseLink.