【问题标题】:Overwritten field when persisting with JPA使用 JPA 持久化时覆盖的字段
【发布时间】:2014-07-03 17:39:26
【问题描述】:

在测试我的模型的持久性时,我会覆盖一个属性。我正在运行以下测试:

@Test
public void objectTest() throws Exception {
   tester.testClass(AssetUpdateReserve.class);       
   Assert.assertEquals(tester.getResult().getErrors().size(), 0, "Errors found");   
}

我的 AssetUpdateReserve 实体:

@Entity
@Table(name = "ASSET_UPD_RESERVE")
public class AssetUpdateReserve implements Serializable {

    private static final long serialVersionUID = 6530799190088978893L;

    @EmbeddedId
    @AttributeOverrides({
            @AttributeOverride(name = "partitionId.assetSliceId", column = @Column(name = "PARTITION_ID")),
            @AttributeOverride(name = "partitionId.associatedKey", column = @Column(name = "PARTITION_ID_AK")),
            @AttributeOverride(name = "containerId.id", column = @Column(name = "CONTAINER_ID")),
            @AttributeOverride(name = "containerId.associatedKey", column = @Column(name = "CONTAINER_ID_AK")) })
    private AssetUpdateReserveIndex id;

    // Default JSON/JAXB constructor
    public AssetUpdateReserve() {
    }
}

据此,我应该有一个具有四个属性的主键。但是,关联键中的相同名称会导致其中一个属性被覆盖(在这种特殊情况下,CONTAINER_ID_AK 会覆盖 PARTITION_AD_AK)这使得我的主键只有三个字段。 我试图评论最后一个@AttributeOverride,这解决了问题并且表有 PARTITION_ID_AK 列。但是,我不能直接关闭 CONTAINER_ID_AK。

我的其他实体:

AssetSliceId

@Embeddable
public class AssetSliceId implements Serializable {
    private static final long serialVersionUID = 9065665917069565503L;

    public static final int MAX_VALUE = Integer.MAX_VALUE;

    @Column(name = "ASSET_SLICE_ID")
    private Integer assetSliceId;

    @Column(name = "ID_AK")
    private String associatedKey;

    public AssetSliceId() {
        super();
    }
}

AssetUpdateReserveIndex:

@Embeddable
public class AssetUpdateReserveIndex implements Serializable {
    private static final long serialVersionUID = 1349614023445826884L;

    @Embedded
    @AttributeOverrides({ @AttributeOverride(name = "assetSliceId", column = @Column(name = "SLICE_ID")),
            @AttributeOverride(name = "associatedKey", column = @Column(name = "SLICE_ID_AK")) })    
    private AssetSliceId partitionId;

    @Embedded
    private InstanceId containerId;

    // Default JSON/JAXB constructor
    public AssetUpdateReserveIndex(){
        super();
    }
}

InstanceId

@Embeddable
public class InstanceId implements Serializable {
    private static final long serialVersionUID = -6620668219143108192L;

    @Column(name = "ID")
    private String id;

    @Column(name = "ID_AK")
    private String associatedKey;

    // Apenas para utilizacao TopLink / POF
    public InstanceId() {
    }
}

我的 persistence.xlm 文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 

http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
    <persistence-unit name="jpa-test" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>

        <class>package.persistencetester.model.jpa.attroverride.AssetSliceId</class>      <class>package.persistencetester.model.jpa.attroverride.AssetUpdateReserve</class>       <class>package.persistencetester.model.jpa.attroverride.AssetUpdateReserveIndex</class>       <class>package.persistencetester.model.jpa.attroverride.InstanceId</class      <class>package.persistencetester.model.jpa.attroverride.SubscriptionID</class>

            <properties>
            <!-- Default Login using Oracle for EclipseLink's internal connection pool -->

            <!--  HSQL -->
            <property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:hsql://localhost/persistencetesterdb"/>
            <property name="javax.persistence.jdbc.user" value="sa"/>
            <property name="javax.persistence.jdbc.password" value=""/>

            <property name="eclipselink.logging.thread" value="false" />
            <property name="eclipselink.logging.session" value="false" />
            <property name="eclipselink.logging.exceptions" value="false" />
            <property name="eclipselink.logging.timestamp" value="false" />
            <property name="eclipselink.logging.level" value="FINE" />
            </properties>
        </persistence-unit>
</persistence>

最后是日志:

Call: DROP TABLE ASSET_UPD_RESERVE
Query: DataModifyQuery(sql="DROP TABLE ASSET_UPD_RESERVE")
[EL Fine]: sql: Connection(1549646215)--CREATE TABLE ASSET_UPD_RESERVE (CONTAINER_ID_AK VARCHAR(255) NOT NULL, CONTAINER_ID VARCHAR(255) NOT NULL, PARTITION_ID INTEGER NOT NULL, PARTITION_ID_AK VARCHAR(255), PRIMARY KEY (CONTAINER_ID_AK, CONTAINER_ID, PARTITION_ID))
2014-07-03 18:20:06 INFO  - =============================================================================
2014-07-03 18:20:06 INFO  - Testing: class package.persistencetester.model.jpa.attroverride.AssetUpdateReserve
2014-07-03 18:20:06 DEBUG - Persisting...
[EL Fine]: sql: Connection(1549646215)--INSERT INTO ASSET_UPD_RESERVE (CONTAINER_ID_AK, CONTAINER_ID, PARTITION_ID, PARTITION_ID_AK) VALUES (?, ?, ?, ?)
    bind => [str3, str2, 1, str1]
2014-07-03 18:20:06 DEBUG - Retrieving...
2014-07-03 18:20:06 FATAL - [ERROR] Unexpected problem while persisting/retrieving following object:
{"package.persistencetester.model.jpa.attroverride.AssetUpdateReserve": {"id": {"partitionId": {"assetSliceId": 1,"associatedKey": "str1"},"containerId": {"id": "str2","associatedKey": "str3"}}}}
javax.persistence.PersistenceException: Exception [EclipseLink-202] (Eclipse Persistence Services - 2.5.1.v20130918-f2b9fc5): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: An internal error occurred accessing the primary key object [package.persistencetester.model.jpa.attroverride.AssetUpdateReserveIndex@6dc27e82].
Internal Exception: java.lang.NoSuchFieldException: id
Descriptor: RelationalDescriptor(package.persistencetester.model.jpa.attroverride.AssetUpdateReserve --> [DatabaseTable(ASSET_UPD_RESERVE)])
    at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.getIdentifier(EntityManagerFactoryDelegate.java:717)
    at package.persistencetester.tester.jpa.bd.Datasource.getObjectId(Datasource.java:132)
    at package.persistencetester.tester.jpa.bd.Datasource.retrieveByObject(Datasource.java:127)
    at package.persistencetester.tester.jpa.JpaTester.testObjectPersistence(JpaTester.java:175)
    at package.persistencetester.tester.jpa.JpaTester.testClass(JpaTester.java:142)
    at package.persistencetester.tester.jpa.JpaTesterTest.objectTest(JpaTesterTest.java:34)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:714)
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
    at org.testng.TestRunner.privateRun(TestRunner.java:767)
    at org.testng.TestRunner.run(TestRunner.java:617)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
    at org.testng.SuiteRunner.run(SuiteRunner.java:240)
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
    at org.testng.TestNG.run(TestNG.java:1057)
    at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
    at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
    at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)
Caused by: Exception [EclipseLink-202] (Eclipse Persistence Services - 2.5.1.v20130918-f2b9fc5): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: An internal error occurred accessing the primary key object [package.persistencetester.model.jpa.attroverride.AssetUpdateReserveIndex@6dc27e82].
Internal Exception: java.lang.NoSuchFieldException: id
Descriptor: RelationalDescriptor(package.persistencetester.model.jpa.attroverride.AssetUpdateReserve --> [DatabaseTable(ASSET_UPD_RESERVE)])
    at org.eclipse.persistence.exceptions.DescriptorException.errorUsingPrimaryKey(DescriptorException.java:1937)
    at org.eclipse.persistence.internal.jpa.CMP3Policy$FieldAccessor.setValue(CMP3Policy.java:697)
    at org.eclipse.persistence.descriptors.CMPPolicy.createPrimaryKeyInstance(CMPPolicy.java:460)
    at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.getIdentifier(EntityManagerFactoryImpl.java:90)
    at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.getIdentifier(EntityManagerFactoryDelegate.java:715)
    ... 29 more
Caused by: java.lang.NoSuchFieldException: id
    at java.lang.Class.getDeclaredField(Class.java:1948)
    at org.eclipse.persistence.internal.security.PrivilegedAccessHelper.findDeclaredField(PrivilegedAccessHelper.java:67)
    at org.eclipse.persistence.internal.security.PrivilegedAccessHelper.findDeclaredField(PrivilegedAccessHelper.java:73)
    at org.eclipse.persistence.internal.security.PrivilegedAccessHelper.getField(PrivilegedAccessHelper.java:223)
    at org.eclipse.persistence.internal.jpa.CMP3Policy$FieldAccessor.setValue(CMP3Policy.java:693)
    ... 32 more
[EL Config]: connection: Connection(1549646215)--disconnect
[EL Info]: connection: file:/C:/Users/x01709/workspace2/persistence-tester/src/core/target/test-classes/_jpa-test logout successful
[EL Config]: connection: Connection(1495651843)--disconnect

注意:在日志中你可以看到创建表和主键只有3个属性,但是当插入时,四个都有

【问题讨论】:

    标签: java jpa eclipselink


    【解决方案1】:

    根据JPA API Doc,“不支持在嵌入式 id 类中定义的关系映射。”

    因为containerIdpartitionId 都包含一个名为associatedKey 的字段,并且它们不能映射到@EmbeddedId 类中的单独实体,所以创建的表中没有包含所有四个值主键(因为它看到associatedKey 两次,并丢弃重复项)。

    【讨论】:

      【解决方案2】:

      对对象关系映射没有太多经验,但如果你的问题是有两个同名的数据,我想你可以使用@ AssociationOverride'会显示一个链接,http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=embedded_associationOverride这就是你想要的,我认为可以帮助您的页面的一部分是:

          @Embedded  
      @AttributeOverrides(  {  
          @AttributeOverride(name="pesoMaximoEnKg", column = @Column(name="pesoMaximoEnKgConductor")),  
      }  
      @AssociationOverrides({  
          @AssociationOverride(name="cinturon",joinColumns=@JoinColumn(name="cinturonConductor_id")),  
      })  
      Asiento asientoConductor;
      
      
      @Embedded  
      @AttributeOverrides(  {  
          @AttributeOverride(name="pesoMaximoEnKg", column = @Column(name="pesoMaximoEnKgCopiloto")),  
      }  
      @AssociationOverrides({  
          @AssociationOverride(name="cinturon",joinColumns=@JoinColumn(name="cinturonCopiloto_id")),  
      })  
      Asiento asientoCopiloto;
      

      P.S:页面是西班牙语的,但我认为谷歌翻译会做得很好。 如果不是您想要的或不为您服务,我会通知我删除。

      【讨论】:

        【解决方案3】:

        如果您查看“扁平化”AssetUpdateReserveIndex 结构,您有两个相同属性名称 (associatedKey) 的映射,后者会覆盖前者。我预计 EclipseLink 会出现某种验证异常,但您在日志中看到的内容(创建表的 3 个属性,插入的 4 个属性)可能表明它们没有完全涵盖这种特殊情况。简单的解决方案是更改冲突字段之一的名称。

        【讨论】:

          猜你喜欢
          • 2010-11-23
          • 2011-12-22
          • 2013-01-02
          • 2013-11-12
          • 2013-02-25
          • 2012-01-17
          • 2011-12-01
          • 2019-07-17
          • 2011-10-06
          相关资源
          最近更新 更多