OpenJPA
  1. OpenJPA
  2. OPENJPA-660

ClassCastException when using OneToMany Relation and collection is subclass using Discriminator with SINGLE_TABLE strategy.

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.0.0, 1.0.1, 1.0.2, 1.0.3, 1.0.4, 1.1.0, 1.1.1, 1.2.0
    • Fix Version/s: 1.2.0
    • Component/s: jpa
    • Labels:
      None

      Description

      If the entity has OneToMany relation and collection is declared as subclass which uses SINGLE_TABLE inheritance strategy, it fetches all rows irrespective of Discriminator value and throws ClassCastException.

      There is entity Department (table dept) having OneToMany relation with another entity FullTimeEmployee.

      @OneToMany (mappedBy="dept", cascade=CascadeType.ALL)
      private Collection<FullTimeEmployee> fullTimeEmployees;

      There is abstract class Employee with
      @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
      @DiscriminatorColumn(name="TYPE")

      There are two entity classes FullTimeEmployee and PartTimeEmployee which extends Employee (table emp) with Discriminator values 'F' and 'P' respectively.

      Now, suppose emp table contains 2 rows of PartTimeEmployee and 2 rows of FullTimeEmployee and if test class fetches Department object and calls dept.getFullTimeEmployees(), it throws ClassCastException as it gets 4 rows and doesn't use discriminator and subclass type while generating SQL query.

      1. testInheritance.zip
        22 kB
        Vikram Bhatia
      2. patch.txt
        4 kB
        Fay Wang

        Activity

        Hide
        Fay Wang added a comment -

        The attached patch fixes this problem. To load a toMany relationship, there is normally a foreign key corresponing to the primary key in the owner class in the where clause. The value of the primary key in the owner class is passed via the argument sm to the load method. The parameter problem exposed by OPENJPA-660 is the missing non-foreign key parameters. The fix is to detect any non-FK parameters and add them to the parameter list.

        Show
        Fay Wang added a comment - The attached patch fixes this problem. To load a toMany relationship, there is normally a foreign key corresponing to the primary key in the owner class in the where clause. The value of the primary key in the owner class is passed via the argument sm to the load method. The parameter problem exposed by OPENJPA-660 is the missing non-foreign key parameters. The fix is to detect any non-FK parameters and add them to the parameter list.
        Hide
        Vikram Bhatia added a comment -

        Using <property name="openjpa.jdbc.QuerySQLCache" value="false"/> has resolved the issue. Please close it.

        Show
        Vikram Bhatia added a comment - Using <property name="openjpa.jdbc.QuerySQLCache" value="false"/> has resolved the issue. Please close it.
        Hide
        Vikram Bhatia added a comment -

        Thanks Pinaki for the suggestion, but it is causing

        2640 testInheritance TRACE [main] openjpa.jdbc.SQL - <t 6889270, conn 20693770> executing prepstmnt 89154
        06 SELECT t0.ssn, t0.type, t0.salary FROM EMP t0 WHERE t0.DEPT_NAME = ? AND t0.type = ? [params=(String) Mat
        hs]
        2656 testInheritance TRACE [main] openjpa.jdbc.SQL - <t 6889270, conn 20693770> [0 ms] spent
        E
        Time: 3.281
        There was 1 error:
        1) testInheritance(com.test.jpa.inheritance.TestCollection)<openjpa-1.2.0-SNAPSHOT-r422266:676787 nonfatal g
        eneral error> org.apache.openjpa.persistence.PersistenceException: ORA-01008: not all variables bound

        {prepstmnt 5084131 SELECT t0.ssn, t0.type, t0.salary FROM EMP t0 WHERE t0.DEPT_NAME = ? AND t0.type = ? [pa rams=(String) Maths]} [code=1008, state=72000]
        at org.apache.openjpa.jdbc.sql.DBDictionary.narrow(DBDictionary.java:4228)
        at org.apache.openjpa.jdbc.sql.DBDictionary.newStoreException(DBDictionary.java:4193)
        at org.apache.openjpa.jdbc.sql.SQLExceptions.getStore(SQLExceptions.java:102)
        at org.apache.openjpa.jdbc.sql.SQLExceptions.getStore(SQLExceptions.java:88)
        at org.apache.openjpa.jdbc.sql.SQLExceptions.getStore(SQLExceptions.java:64)
        at org.apache.openjpa.jdbc.kernel.JDBCStoreManager.load(JDBCStoreManager.java:613)
        at org.apache.openjpa.kernel.DelegatingStoreManager.load(DelegatingStoreManager.java:116)
        at org.apache.openjpa.kernel.ROPStoreManager.load(ROPStoreManager.java:78)
        at org.apache.openjpa.kernel.StateManagerImpl.loadFields(StateManagerImpl.java:2919)
        at org.apache.openjpa.kernel.StateManagerImpl.loadField(StateManagerImpl.java:2997)
        at org.apache.openjpa.kernel.StateManagerImpl.beforeAccessField(StateManagerImpl.java:1491)
        at org.apache.openjpa.kernel.StateManagerImpl.accessingField(StateManagerImpl.java:1476)
        at com.test.jpa.inheritance.Department.pcGetfullTimeEmployees(Department.java)
        at com.test.jpa.inheritance.Department.getFullTimeEmployees(Department.java:30)
        at com.test.jpa.inheritance.TestCollection.testInheritance(TestCollection.java:52)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        Caused by: org.apache.openjpa.lib.jdbc.ReportingSQLException: ORA-01008: not all variables bound
        {prepstmnt 5084131 SELECT t0.ssn, t0.type, t0.salary FROM EMP t0 WHERE t0.DEPT_NAME = ? AND t0.type = ? [pa rams=(String) Maths]}

        [code=1008, state=72000]
        at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.wrap(LoggingConnectionDecorator.java:192)
        at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.access$700(LoggingConnectionDecorator.java
        :57)
        at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator$LoggingConnection$LoggingPreparedStatement
        .executeQuery(LoggingConnectionDecorator.java:852)
        at org.apache.openjpa.lib.jdbc.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.
        java:262)
        at org.apache.openjpa.jdbc.kernel.JDBCStoreManager$CancelPreparedStatement.executeQuery(JDBCStoreMan
        ager.java:1494)
        at org.apache.openjpa.lib.jdbc.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.
        java:252)

        It looks like it is svn r652913 (OPENJPA-407) which has made changes in StoreCollectionFieldStrategy.load() method resulting in this issue.

        ClassMapping mapping = field.getDefiningMapping();
        Object oid = sm.getObjectId();
        Column[] cols = mapping.getPrimaryKeyColumns();
        if (sel == null)
        sel = ((LogicalUnion.UnionSelect)union.getSelects()[0]).
        getDelegate();

        sel.wherePrimaryKey(mapping, cols, cols, oid, store,
        null, null, parmList);

        Show
        Vikram Bhatia added a comment - Thanks Pinaki for the suggestion, but it is causing 2640 testInheritance TRACE [main] openjpa.jdbc.SQL - <t 6889270, conn 20693770> executing prepstmnt 89154 06 SELECT t0.ssn, t0.type, t0.salary FROM EMP t0 WHERE t0.DEPT_NAME = ? AND t0.type = ? [params=(String) Mat hs] 2656 testInheritance TRACE [main] openjpa.jdbc.SQL - <t 6889270, conn 20693770> [0 ms] spent E Time: 3.281 There was 1 error: 1) testInheritance(com.test.jpa.inheritance.TestCollection)<openjpa-1.2.0-SNAPSHOT-r422266:676787 nonfatal g eneral error> org.apache.openjpa.persistence.PersistenceException: ORA-01008: not all variables bound {prepstmnt 5084131 SELECT t0.ssn, t0.type, t0.salary FROM EMP t0 WHERE t0.DEPT_NAME = ? AND t0.type = ? [pa rams=(String) Maths]} [code=1008, state=72000] at org.apache.openjpa.jdbc.sql.DBDictionary.narrow(DBDictionary.java:4228) at org.apache.openjpa.jdbc.sql.DBDictionary.newStoreException(DBDictionary.java:4193) at org.apache.openjpa.jdbc.sql.SQLExceptions.getStore(SQLExceptions.java:102) at org.apache.openjpa.jdbc.sql.SQLExceptions.getStore(SQLExceptions.java:88) at org.apache.openjpa.jdbc.sql.SQLExceptions.getStore(SQLExceptions.java:64) at org.apache.openjpa.jdbc.kernel.JDBCStoreManager.load(JDBCStoreManager.java:613) at org.apache.openjpa.kernel.DelegatingStoreManager.load(DelegatingStoreManager.java:116) at org.apache.openjpa.kernel.ROPStoreManager.load(ROPStoreManager.java:78) at org.apache.openjpa.kernel.StateManagerImpl.loadFields(StateManagerImpl.java:2919) at org.apache.openjpa.kernel.StateManagerImpl.loadField(StateManagerImpl.java:2997) at org.apache.openjpa.kernel.StateManagerImpl.beforeAccessField(StateManagerImpl.java:1491) at org.apache.openjpa.kernel.StateManagerImpl.accessingField(StateManagerImpl.java:1476) at com.test.jpa.inheritance.Department.pcGetfullTimeEmployees(Department.java) at com.test.jpa.inheritance.Department.getFullTimeEmployees(Department.java:30) at com.test.jpa.inheritance.TestCollection.testInheritance(TestCollection.java:52) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) Caused by: org.apache.openjpa.lib.jdbc.ReportingSQLException: ORA-01008: not all variables bound {prepstmnt 5084131 SELECT t0.ssn, t0.type, t0.salary FROM EMP t0 WHERE t0.DEPT_NAME = ? AND t0.type = ? [pa rams=(String) Maths]} [code=1008, state=72000] at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.wrap(LoggingConnectionDecorator.java:192) at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.access$700(LoggingConnectionDecorator.java :57) at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator$LoggingConnection$LoggingPreparedStatement .executeQuery(LoggingConnectionDecorator.java:852) at org.apache.openjpa.lib.jdbc.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement. java:262) at org.apache.openjpa.jdbc.kernel.JDBCStoreManager$CancelPreparedStatement.executeQuery(JDBCStoreMan ager.java:1494) at org.apache.openjpa.lib.jdbc.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement. java:252) It looks like it is svn r652913 ( OPENJPA-407 ) which has made changes in StoreCollectionFieldStrategy.load() method resulting in this issue. ClassMapping mapping = field.getDefiningMapping(); Object oid = sm.getObjectId(); Column[] cols = mapping.getPrimaryKeyColumns(); if (sel == null) sel = ((LogicalUnion.UnionSelect)union.getSelects() [0] ). getDelegate(); sel.wherePrimaryKey(mapping, cols, cols, oid, store, null, null, parmList);
        Hide
        Pinaki Poddar added a comment -

        The test will pass if typed collection fields declare ElementClassCriteria as follows (+ marks added lines)

        @OneToMany (mappedBy="dept", cascade= CascadeType.PERSIST)
        + @ElementClassCriteria
        private Collection<PartTimeEmployee> partTimeEmployees;

        @OneToMany (mappedBy="dept", cascade= CascadeType.PERSIST)
        + @ElementClassCriteria
        private Collection<FullTimeEmployee> fullTimeEmployees;

        Show
        Pinaki Poddar added a comment - The test will pass if typed collection fields declare ElementClassCriteria as follows (+ marks added lines) @OneToMany (mappedBy="dept", cascade= CascadeType.PERSIST) + @ElementClassCriteria private Collection<PartTimeEmployee> partTimeEmployees; @OneToMany (mappedBy="dept", cascade= CascadeType.PERSIST) + @ElementClassCriteria private Collection<FullTimeEmployee> fullTimeEmployees;
        Hide
        Vikram Bhatia added a comment -

        Testcase with junit test TestCollection class.

        Show
        Vikram Bhatia added a comment - Testcase with junit test TestCollection class.

          People

          • Assignee:
            Pinaki Poddar
            Reporter:
            Vikram Bhatia
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development