It'sMe
It'sMe

Reputation: 125

Foreign key as a part of composite primary key and ManyToOne relationship in OpenJPA

I want to create simple database with OpenJPA 2.3.

TableA:
- f_id    PK
- item    PK
- release PK
- b_id    PK
- field1
- field2

TableB:
- id      PK
- name
- date

Where b_id in TableA references to id in TableB (MANY TableA rows to ONE TableB row). b_id is a part of entire composite primary key.

TableA class:

@Entity 
@IdClass(TableA_PK.class)
public class TableA implements Serializable {
    @Id
    private int fId;
    @Id
    private String item;
    @Id
    private String release;
    @Id
    @ManyToOne
    @PrimaryKeyJoinColumn(name="b_id", referencedColumnName="id")
    private TableB tableB;
    @Column
    private String field1;
    @Column
    private String field2;

    public TableA() {}
    //getters, setters, equals, hashCode methods
}

TableA primary key class:

public class TableA_PK implements Serializable {
    private int fId;
    private String item;
    private String release;
    private TableB tableB;

    public TableA_PK() {}
    //getters, setters, equals, hashCode methods
}

TableB class:

 @Entity 
 public class TableB implements Serializable {
    @Id
    @GeneratedValue
    private long id;
    @Column
    private String name;
    @Column
    private Date date;

    @OneToMany(mappedBy="tableB", fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    private List<TableA> rows;

    public TableB() {}
    //getters, setters, equals, hashCode methods
}

When I try to persist TableB object Exception had been thrown:

org.apache.openjpa.persistence.ArgumentException: Attempt to map "model.TableA.tableB" failed: the owning entity is not mapped.

How to fix this?

My theory/explanation: It looks like, when I try to persist TableB object every element of rows must be persisted. But in TableA there is a field private TableB tableB (which is not persisted yet), so we fall into infinity recursion ;).

EDIT:

Full Trace (before changes):

<openjpa-2.3.0-r422266:1540826 fatal user error> org.apache.openjpa.persistence.ArgumentException: Errors encountered while resolving metadata.  See nested exceptions for details.
    at org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:675)
    at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:418)
    at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:389)
    at org.apache.openjpa.jdbc.meta.MappingRepository.getMapping(MappingRepository.java:354)
    at org.apache.openjpa.jdbc.meta.MappingTool.getMapping(MappingTool.java:682)
    at org.apache.openjpa.jdbc.meta.MappingTool.buildSchema(MappingTool.java:754)
    at org.apache.openjpa.jdbc.meta.MappingTool.run(MappingTool.java:652)
    at org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.synchronizeMappings(JDBCBrokerFactory.java:154)
    at org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.synchronizeMappings(JDBCBrokerFactory.java:164)
    at org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.newBrokerImpl(JDBCBrokerFactory.java:122)
    at org.apache.openjpa.kernel.AbstractBrokerFactory.newBroker(AbstractBrokerFactory.java:209)
    at org.apache.openjpa.kernel.DelegatingBrokerFactory.newBroker(DelegatingBrokerFactory.java:155)
    at org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:226)
    at org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:153)
    at org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:59)
    at org.JpaTest.test(JpaTest.java:40)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: <openjpa-2.3.0-r422266:1540826 fatal user error> org.apache.openjpa.persistence.ArgumentException: The id class specified by type "class org.model.TableA" does not match the primary key fields of the class.  Make sure your identity class has the same primary keys as your persistent type, including pk field types. Mismatched property: "tableB"
    at org.apache.openjpa.meta.ClassMetaData.validateAppIdClassPKs(ClassMetaData.java:2225)
    at org.apache.openjpa.meta.ClassMetaData.validateAppIdClass(ClassMetaData.java:2099)
    at org.apache.openjpa.meta.ClassMetaData.validateIdentity(ClassMetaData.java:2035)
    at org.apache.openjpa.meta.ClassMetaData.validateMeta(ClassMetaData.java:1947)
    at org.apache.openjpa.meta.ClassMetaData.resolve(ClassMetaData.java:1808)
    at org.apache.openjpa.meta.MetaDataRepository.processBuffer(MetaDataRepository.java:829)
    at org.apache.openjpa.meta.MetaDataRepository.resolveMeta(MetaDataRepository.java:726)
    at org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:650)
    ... 38 more
NestedThrowables:
<openjpa-2.3.0-r422266:1540826 fatal user error> org.apache.openjpa.persistence.ArgumentException: Attempt to map "org.model.TableA.tableB" failed: the owning entity is not mapped.
    at org.apache.openjpa.jdbc.meta.MappingInfo.assertTable(MappingInfo.java:628)
    at org.apache.openjpa.jdbc.meta.MappingInfo.createForeignKey(MappingInfo.java:1080)
    at org.apache.openjpa.jdbc.meta.ValueMappingInfo.getTypeJoin(ValueMappingInfo.java:115)
    at org.apache.openjpa.jdbc.meta.ValueMappingInfo.getTypeJoin(ValueMappingInfo.java:92)
    at org.apache.openjpa.jdbc.meta.strats.RelationFieldStrategy.map(RelationFieldStrategy.java:166)
    at org.apache.openjpa.jdbc.meta.FieldMapping.setStrategy(FieldMapping.java:146)
    at org.apache.openjpa.jdbc.meta.RuntimeStrategyInstaller.installStrategy(RuntimeStrategyInstaller.java:82)
    at org.apache.openjpa.jdbc.meta.FieldMapping.resolveMapping(FieldMapping.java:496)
    at org.apache.openjpa.jdbc.meta.FieldMapping.resolve(FieldMapping.java:461)
    at org.apache.openjpa.jdbc.meta.strats.RelationToManyInverseKeyFieldStrategy.map(RelationToManyInverseKeyFieldStrategy.java:135)
    at org.apache.openjpa.jdbc.meta.strats.RelationCollectionInverseKeyFieldStrategy.map(RelationCollectionInverseKeyFieldStrategy.java:94)
    at org.apache.openjpa.jdbc.meta.FieldMapping.setStrategy(FieldMapping.java:146)
    at org.apache.openjpa.jdbc.meta.RuntimeStrategyInstaller.installStrategy(RuntimeStrategyInstaller.java:82)
    at org.apache.openjpa.jdbc.meta.FieldMapping.resolveMapping(FieldMapping.java:496)
    at org.apache.openjpa.jdbc.meta.FieldMapping.resolve(FieldMapping.java:461)
    at org.apache.openjpa.jdbc.meta.ClassMapping.resolveMapping(ClassMapping.java:854)
    at org.apache.openjpa.meta.ClassMetaData.resolve(ClassMetaData.java:1811)
    at org.apache.openjpa.meta.MetaDataRepository.processBuffer(MetaDataRepository.java:829)
    at org.apache.openjpa.meta.MetaDataRepository.resolveMapping(MetaDataRepository.java:784)
    at org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:664)
    at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:418)
    at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:389)
    at org.apache.openjpa.jdbc.meta.MappingRepository.getMapping(MappingRepository.java:354)
    at org.apache.openjpa.jdbc.meta.MappingTool.getMapping(MappingTool.java:682)
    at org.apache.openjpa.jdbc.meta.MappingTool.buildSchema(MappingTool.java:754)
    at org.apache.openjpa.jdbc.meta.MappingTool.run(MappingTool.java:652)
    at org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.synchronizeMappings(JDBCBrokerFactory.java:154)
    at org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.synchronizeMappings(JDBCBrokerFactory.java:164)
    at org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.newBrokerImpl(JDBCBrokerFactory.java:122)
    at org.apache.openjpa.kernel.AbstractBrokerFactory.newBroker(AbstractBrokerFactory.java:209)
    at org.apache.openjpa.kernel.DelegatingBrokerFactory.newBroker(DelegatingBrokerFactory.java:155)
    at org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:226)
    at org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:153)
    at org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:59)
    at org.JpaTest.test(JpaTest.java:40)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Full Trace, after changes (when I changed type of tableB in TableA_PK on long):

<openjpa-2.3.0-r422266:1540826 nonfatal general error> org.apache.openjpa.persistence.PersistenceException: org.model.TableB cannot be cast to java.lang.Number
    at org.apache.openjpa.kernel.BrokerImpl.persistAll(BrokerImpl.java:2526)
    at org.apache.openjpa.kernel.SingleFieldManager.persist(SingleFieldManager.java:279)
    at org.apache.openjpa.kernel.StateManagerImpl.cascadePersist(StateManagerImpl.java:3081)
    at org.apache.openjpa.kernel.BrokerImpl.persistInternal(BrokerImpl.java:2703)
    at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2604)
    at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2587)
    at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2491)
    at org.apache.openjpa.kernel.DelegatingBroker.persist(DelegatingBroker.java:1077)
    at org.apache.openjpa.persistence.EntityManagerImpl.persist(EntityManagerImpl.java:716)
    at org.JpaTest.test(JpaTest.java:43)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.ClassCastException: org.model.TableB cannot be cast to java.lang.Number
    at org.apache.openjpa.util.ApplicationIds$PrimaryKeyFieldManager.fetchLongField(ApplicationIds.java:669)
    at org.apache.openjpa.enhance.org$model$TableA$pcsubclass.pcCopyKeyFieldsToObjectId(Unknown Source)
    at org.apache.openjpa.enhance.PCRegistry.copyKeyFieldsToObjectId(PCRegistry.java:169)
    at org.apache.openjpa.util.ApplicationIds.fromPKValues(ApplicationIds.java:224)
    at org.apache.openjpa.enhance.ReflectingPersistenceCapable.pcNewObjectIdInstance(ReflectingPersistenceCapable.java:277)
    at org.apache.openjpa.util.ApplicationIds.create(ApplicationIds.java:427)
    at org.apache.openjpa.kernel.BrokerImpl.persistInternal(BrokerImpl.java:2675)
    at org.apache.openjpa.kernel.BrokerImpl.persistAll(BrokerImpl.java:2521)
    ... 32 more

Full Trace, after changes (when I changed type of tableB in TableA_PK on Long, and type of id in TableB on Long):

<openjpa-2.3.0-r422266:1540826 nonfatal general error> org.apache.openjpa.persistence.PersistenceException: Can not set java.lang.Long field org.model.TableA_PK.tableB to org.model.TableB
    at org.apache.openjpa.kernel.BrokerImpl.persistAll(BrokerImpl.java:2526)
    at org.apache.openjpa.kernel.SingleFieldManager.persist(SingleFieldManager.java:279)
    at org.apache.openjpa.kernel.StateManagerImpl.cascadePersist(StateManagerImpl.java:3081)
    at org.apache.openjpa.kernel.BrokerImpl.persistInternal(BrokerImpl.java:2703)
    at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2604)
    at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2587)
    at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2491)
    at org.apache.openjpa.kernel.DelegatingBroker.persist(DelegatingBroker.java:1077)
    at org.apache.openjpa.persistence.EntityManagerImpl.persist(EntityManagerImpl.java:716)
    at org.JpaTest.test(JpaTest.java:49)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.IllegalArgumentException: Can not set java.lang.Long field org.model.TableA_PK.tableB to org.model.TableB
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(Unknown Source)
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(Unknown Source)
    at sun.reflect.UnsafeObjectFieldAccessorImpl.set(Unknown Source)
    at java.lang.reflect.Field.set(Unknown Source)
    at org.apache.openjpa.enhance.Reflection.set(Reflection.java:538)
    at org.apache.openjpa.enhance.org$model$RowData$pcsubclass.pcCopyKeyFieldsToObjectId(Unknown Source)
    at org.apache.openjpa.enhance.PCRegistry.copyKeyFieldsToObjectId(PCRegistry.java:169)
    at org.apache.openjpa.util.ApplicationIds.fromPKValues(ApplicationIds.java:224)
    at org.apache.openjpa.enhance.ReflectingPersistenceCapable.pcNewObjectIdInstance(ReflectingPersistenceCapable.java:277)
    at org.apache.openjpa.util.ApplicationIds.create(ApplicationIds.java:427)
    at org.apache.openjpa.kernel.BrokerImpl.persistInternal(BrokerImpl.java:2675)
    at org.apache.openjpa.kernel.BrokerImpl.persistAll(BrokerImpl.java:2521)
    ... 32 more
Caused by: java.lang.IllegalArgumentException: Error while setting value org.model.TableB@982c7dfd of class org.model.TableB on field private java.lang.Long org.model.TableA_PK.tableB of instance org.model.TableA_PK@e426b053 by reflection.    
    at org.apache.openjpa.enhance.Reflection.wrapReflectionException(Reflection.java:334)
    at org.apache.openjpa.enhance.Reflection.set(Reflection.java:540)
    ... 39 more

EDIT AFTER @Gas ANSWER

I did just like you said. But I have problem with persist entire TableB object, my test class:

public class JpaTest {

    @Test
    public void test() {
        TableB tb = new TableB();
        tb.setName("testing");
        tb.setDate(new Date());

        TableA ta1 = new TableA();
        ta1.setFId(1);
        ta1.setItem("item1");
        ta1.setRelease("release1");
        ta1.setField1("f1");
        ta1.setField2("f2");

        TableA ta2 = new TableA();
        ta2.setFId(2);
        ta2.setItem("item2");
        ta2.setRelease("release2");
        ta2.setField1("F1");
        ta2.setField2("F2");

        List<TableA> alist = new ArrayList<TableA>();
        alist.add(ta1);
        alist.add(ta2);

        tb.setRows(alist);

        EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("rd-jpa");
        EntityManager em = entityManagerFactory.createEntityManager();
        EntityTransaction userTransaction = em.getTransaction();
        userTransaction.begin();
        em.persist(tb);
        userTransaction.commit();
        em.clear();
        em.close();
    }

I have Exception:

org.apache.openjpa.persistence.RollbackException: The transaction has been rolled back.  See the nested exceptions for details on the errors that occurred.
(...)
Caused by: org.apache.openjpa.lib.jdbc.ReportingSQLException: ERROR: null value in column "b_id" violates not-null constraint

Why? I thought what it'll persist tb first, and then every element in rows will have know about obtained TableB.id (thanks to tableB field in TableA class). What's wrong with this?

If I add two lines in Test before persist:

ta1.setTableB(tb);
ta2.setTableB(tb);

this Exception will be throw:

Caused by: java.lang.ClassCastException: org.model.TableB cannot be cast to java.lang.Number

(Do I need set tableB field in TableA by myself?)

How to persist TableB object?

EDIT 3: persistence.xml

<?xml version="1.0" encoding="UTF-8" ?>
<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_2_0.xsd"
    version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
    <persistence-unit name="rd-jpa" transaction-type="RESOURCE_LOCAL">
        <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
        <class>org.model.TableA</class>
        <class>org.model.TableB</class>
        <properties>
            <property name="openjpa.ConnectionURL"
                value="jdbc:postgresql://localhost:5432/mydb" />
            <property name="openjpa.ConnectionDriverName" value="org.postgresql.Driver" />
            <property name="openjpa.ConnectionUserName" value="postgres" />
            <property name="openjpa.ConnectionPassword" value="postgres" />
            <property name="openjpa.DynamicEnhancementAgent" value="true" />
            <property name="openjpa.RuntimeUnenhancedClasses" value="supported" />
            <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)" />
        </properties>
    </persistence-unit>
</persistence>

Upvotes: 0

Views: 1442

Answers (1)

Gas
Gas

Reputation: 18020

This works for me for the following code. Changed the long tableB in TableA_PK and @JoinColumn in TableA.

TABLEA

@Entity 
@IdClass(TableA_PK.class)
public class TableA implements Serializable {
    @Id
    private int fId;
    @Id
    private String item;
    @Id
    private String release;
    @Id
    @ManyToOne
    @JoinColumn(name="b_id")
    private TableB tableB;
    @Column
    private String field1;
    @Column
    private String field2;

TABLEA_PK

public class TableA_PK implements Serializable {
    private int fId;
    private String item;
    private String release;
    private long tableB;

    public TableA_PK() {}
    //getters, setters, equals, hashCode methods

TABLEB

@Entity 
public class TableB implements Serializable {
   @Id
   @GeneratedValue
   private long id;
   @Column
   private String name;
   @Column
   private Date date;

   @OneToMany(mappedBy="tableB")
   private List<TableA> rows;

   public TableB() {}
   //getters, setters, equals, hashCode methods

UPDATE after comment
Unfortunately generated value is not supported for derived keys and its not known before item is inserted. So you need first to persist tableB item and then add rows. Check the following code:

    TableB tableb = new TableB();
    tableb.setDate(new Date());
    tableb.setName("tableb2");
    em.persist(tableb);  // fills tableb id
    System.out.println(tableb); 
    TableA tableA = new TableA();
    tableA.setfId((int) new Date().getTime());
    tableA.setField1("field1");
    tableA.setField2("field2");
    tableA.setItem("item2");
    tableA.setRelease("1");
    tableA.setTableB(tableb);
    ArrayList<TableA> rows = new ArrayList<TableA>();
    rows.add(tableA);
    tableb.setRows(rows);
    em.merge(tableb);  // inserts tablea objects, you could also just persist tableA items

Upvotes: 1

Related Questions