Отображение JPA (Hibernate, EclipseLink): почему этот код не работает (цепочка из двух отношений, использующих JPA 2.0, составной пакет @EmbeddedId PK-FK)? - PullRequest
5 голосов
/ 27 ноября 2010

У меня есть три таблицы:

CREATE TABLE PostAddresses
(
  contact_id INTEGER NOT NULL,
  ordinal_nbr SMALLINT NOT NULL,
  PRIMARY KEY (contact_id, ordinal_nbr)
);

CREATE TABLE Foos
(
  contact_id INTEGER NOT NULL,
  ordinal_nbr SMALLINT NOT NULL,
  PRIMARY KEY (contact_id, ordinal_nbr),
  FOREIGN KEY (contact_id, ordinal_nbr) REFERENCES PostAddresses (contact_id, ordinal_nbr)
);

CREATE TABLE Bars
(
  contact_id INTEGER NOT NULL,
  ordinal_nbr SMALLINT NOT NULL,
  numba INTEGER NOT NULL,
  PRIMARY KEY (contact_id, ordinal_nbr, numba),
  FOREIGN KEY (contact_id, ordinal_nbr) REFERENCES Foos (contact_id, ordinal_nbr)
);

Простая логика: Bars -> Foos -> PostAddresses всех (contact_id, ordinal_nbr), что бы это ни значило.

Здесь шесть сущностей и соответствующие классы составных ключей.

@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"), @JoinColumn(name = "ordinal_nbr", referencedColumnName = "ordinal_nbr")})
    private PostAddress postAddress = null;

    ...
}

@Embeddable
public class FooId implements Serializable
{
    @Embedded
    private PostAddressId postAddressId; //just one field!

    ...
}

@Entity
@Table(name = "Bars")
public class Bar implements Serializable
{
    @EmbeddedId
    private BarId embeddedId;

    ...
}

@Embeddable
public class BarId implements Serializable
{
    @Embedded
    private FooId fooId;

    @Column(name = "numba")
    private Integer numba;

    ...
}

В этом нет ничего особенного, Bar ссылается на Foo, Foo ссылается на PostAddress, все через класс составного ключа. Поскольку внешние ключи составные и являются частью PK, я должен вложить классы ID в классы ID. Я думал, что это правильно. Тем не менее, я получаю следующие трассировки стека с Hibernate 3.6 и EclipseLink 2.2.0

Hibernate:

org.hibernate.AssertionFailure: Unexpected nested component on the referenced entity when mapping a @MapsId: tld.transmuc.model.Foo
    at org.hibernate.cfg.CopyIdentifierComponentSecondPass.doSecondPass(CopyIdentifierComponentSecondPass.java:101)
    at org.hibernate.cfg.Configuration.processSecondPassesOfType(Configuration.java:1424)
    at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1388)
    at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1345)
    at org.hibernate.ejb.Ejb3Configuration.buildMappings(Ejb3Configuration.java:1477)
    at org.hibernate.ejb.EventListenerConfigurator.configure(EventListenerConfigurator.java:193)
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:1096)
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:278)
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:362)
    at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:56)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:48)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:32)
    at tld.transmuc.Main.main(Main.java:27)
Exception in thread "main" javax.persistence.PersistenceException: [PersistenceUnit: transmuc] Unable to configure EntityManagerFactory
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:374)
    at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:56)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:48)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:32)
    at tld.transmuc.Main.main(Main.java:27)
Caused by: org.hibernate.AssertionFailure: Unexpected nested component on the referenced entity when mapping a @MapsId: tld.transmuc.model.Foo
    at org.hibernate.cfg.CopyIdentifierComponentSecondPass.doSecondPass(CopyIdentifierComponentSecondPass.java:101)
    at org.hibernate.cfg.Configuration.processSecondPassesOfType(Configuration.java:1424)
    at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1388)
    at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1345)
    at org.hibernate.ejb.Ejb3Configuration.buildMappings(Ejb3Configuration.java:1477)
    at org.hibernate.ejb.EventListenerConfigurator.configure(EventListenerConfigurator.java:193)
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:1096)
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:278)
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:362)
    ... 4 more

EclipseLink:

Exception in thread "main" Local Exception Stack: 
Exception [EclipseLink-30005] (Eclipse Persistence Services - 2.2.0.v20101118-r8514): org.eclipse.persistence.exceptions.PersistenceUnitLoadingException
Exception Description: An exception was thrown while searching for persistence archives with ClassLoader: sun.misc.Launcher$AppClassLoader@1f7182c1
Internal Exception: javax.persistence.PersistenceException: Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.2.0.v20101118-r8514): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Predeployment of PersistenceUnit [transmuc] failed.
Internal Exception: java.lang.NullPointerException
    at org.eclipse.persistence.exceptions.PersistenceUnitLoadingException.exceptionSearchingForPersistenceResources(PersistenceUnitLoadingException.java:126)
    at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:136)
    at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:65)
    at javax.persistence.Persistence.createEntityManagerFactory(Unknown Source)
    at javax.persistence.Persistence.createEntityManagerFactory(Unknown Source)
    at tld.transmuc.Main.main(Main.java:27)
Caused by: javax.persistence.PersistenceException: Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.2.0.v20101118-r8514): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Predeployment of PersistenceUnit [transmuc] failed.
Internal Exception: java.lang.NullPointerException
    at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:1021)
    at org.eclipse.persistence.internal.jpa.deployment.JPAInitializer.callPredeploy(JPAInitializer.java:95)
    at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:127)
    ... 4 more
Caused by: Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.2.0.v20101118-r8514): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Predeployment of PersistenceUnit [transmuc] failed.
Internal Exception: java.lang.NullPointerException
    at org.eclipse.persistence.exceptions.EntityManagerSetupException.predeployFailed(EntityManagerSetupException.java:210)
    ... 7 more
Caused by: java.lang.NullPointerException
    at org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.EmbeddedIdAccessor.process(EmbeddedIdAccessor.java:189)
    at org.eclipse.persistence.internal.jpa.metadata.MetadataDescriptor.processMappingAccessors(MetadataDescriptor.java:1417)
    at org.eclipse.persistence.internal.jpa.metadata.accessors.classes.ClassAccessor.processMappingAccessors(ClassAccessor.java:1405)
    at org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EntityAccessor.processMappingAccessors(EntityAccessor.java:1061)
    at org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EntityAccessor.process(EntityAccessor.java:601)
    at org.eclipse.persistence.internal.jpa.metadata.MetadataProject.processStage2(MetadataProject.java:1464)
    at org.eclipse.persistence.internal.jpa.metadata.MetadataProcessor.processORMMetadata(MetadataProcessor.java:483)
    at org.eclipse.persistence.internal.jpa.deployment.PersistenceUnitProcessor.processORMetadata(PersistenceUnitProcessor.java:453)
    at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:975)
    ... 6 more

EclipseLink абсолютно не подсказывает мне, какой класс является нарушающим. По крайней мере, Hibernate говорит мне о проблеме с аннотацией @MapsId и классом Foo:

org.hibernate.AssertionFailure: Unexpected nested component on the referenced entity when mapping a @MapsId: tld.transmuc.model.Foo

Что здесь не так?

PS: я могу собрать SSCCE, просто спросить, нужен ли он вам (JavaSE, HSQLDB, Ant, Hibernate 3.6).

1 Ответ

2 голосов
/ 29 ноября 2010

Простое удаление аннотации @Embedded из типов EmbeddedId, которые ссылаются на зависимые EmbeddedIds, может решить вашу проблему .:

    @Embeddable
    public class FooId implements Serializable
    {
        // no annotation.
        private PostAddressId postAddressId; //just one field!

        ...
    }

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

(EDIT): Еще одной проблемой является использование FooId.Этот класс не должен использоваться.Класс ID для Foo Enitity - это PostAddressId, а "postAddress" в OneToOne следует просто пометить @Id, а не @MapsId.Аналогично, для BarId не должно быть определено Embedded, но оно должно напрямую ссылаться на PostAddressId.Bar Bar Mapping, который ссылается на PostAddress, должен использовать MapsId.

Пожалуйста, сообщите об ошибке в EclipseLink для ужасного исключения, и если удаление @Embedded и других обновлений в редактировании не решает вашу проблему, пожалуйста, отправьте ошибку EclipseLink дляэто также.

...