JPA(Hibernate,EclipseLink)映射:为什么此代码不起作用(使用JPA 2.0的2个关系链,@EmbeddedId复合PK-FK)? [英] JPA (Hibernate, EclipseLink) mapping: why doesn't this code work (chain of 2 relationships using JPA 2.0, @EmbeddedId composite PK-FK)?

查看:71
本文介绍了JPA(Hibernate,EclipseLink)映射:为什么此代码不起作用(使用JPA 2.0的2个关系链,@EmbeddedId复合PK-FK)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有三个表:

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-> PostAddress通过(contact_id,ordinal_nbr)表示所有含义,

Simple logic: Bars -> Foos -> PostAddresses all by (contact_id, ordinal_nbr), whatever it means.

这里有六个实体和各自的组合键类.

Here the six entity and respective composite key classes.

@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中获得了以下堆栈跟踪信息

It's really nothing special, Bar references Foo, Foo references PostAddress, all via composite key class. Since the foreign keys are composite and part of the PK, I must nest the ID classes into the ID classes. I thought this is correct. However, I get the following stack traces with Hibernate 3.6 and EclipseLink 2.2.0

休眠:

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:

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类的问题:

EclipseLink gives me absolutely no hint as to which class is the offending one. At least Hibernate tells me about a problem with the @MapsId annotation and the Foo class:

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).

PS: I can put together an SSCCE, just ask if you need one (JavaSE, HSQLDB, Ant, Hibernate 3.6).

推荐答案

仅从引用从属EmbeddedId的EmbeddedId类型中删除@Embedded批注即可解决您的问题.

Simply removing the @Embedded annotation from within the EmbeddedId types that reference the dependant EmbeddedIds may resolve your issue.:


    @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;
 

(编辑):另一个问题是FooId的使用.不应使用此类. Foo Enitity的ID类是PostAddressId,而OneToOne"postAddress"应该仅标记为@Id而不是@MapsId.同样,BarId不应具有Embedded定义,而应直接引用PostAddressId.引用PostAddress的条形图应使用MapsId.

(EDIT): Another issue is the use of the FooId. This class should not be used. The ID class for Foo Enitity is the PostAddressId and the OneToOne "postAddress" should simply be marked @Id and not @MapsId. Likewise BarId should not have an Embedded defined but should directly reference the PostAddressId. The Bar Mapping that references PostAddress should use MapsId.

请针对可怕的异常针对EclipseLink提交错误;如果删除@Embedded和编辑中的其他更新不能解决您的问题,请也针对此错误提交EclipseLink错误.

Please file a bug against EclipseLink for the terrible exception and if removing the @Embedded and the other updates in the edit does not resolve your issue please file an EclipseLink bug for that as well.

这篇关于JPA(Hibernate,EclipseLink)映射:为什么此代码不起作用(使用JPA 2.0的2个关系链,@EmbeddedId复合PK-FK)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆