EclipseLink: несколько столбцов, один-к-одному, JPA 2.0 @EmbeddedId с использованием @MapsId завершается с ошибкой только для чтения на @JoinColumn (сравниваются производные идентификаторы) - PullRequest
2 голосов
/ 15 мая 2011

У меня есть следующий дизайн:

Действительный 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.

1 Ответ

4 голосов
/ 16 мая 2011

EclipseLink интерпретирует mapsId как означающее, что отношение управляет столбцами contact_id и ordinal_nbr, определенными в вашей таблице Foos.Из-за этого, когда вы помечаете поля отношений как доступные только для чтения, это означает, что для этих полей нет доступных для записи отображений - mapsId сообщает поставщику, что значения должны использоваться из отношения, но отношение только для чтения.

Есть ли какая-то причина, по которой вы используете mapsId вместо того, чтобы просто пометить ваши отношения как идентификатор и затем использовать класс pk?

...