2016-02-08 2 views
0

Я добавляю 2 объекта к базе данных, Person и Student (подкласс Person). Когда я запрашиваю Person, он возвращает каждый экземпляр e дважды. Когда я запрашиваю Student, он возвращает оба экземпляра, хотя Person не является подклассом Student. Код основан на шаблоне jdo-test из datanucleus. Я использую Datanucleus 5.0.0m1.Запросы возвращают дубликаты в JDO/Datanucleus/H2

класс
tx.begin(); 

Person p = new Person(0, "Pete"); 
Student s = new Student(1, "Sarah"); 
pm.makePersistent(p); 
pm.makePersistent(s); 

Query<Person> qP = pm.newQuery(Person.class); 
Collection<Person>cP = (Collection<Person>) qP.execute(); 
for (Person p2: cP) { 
    System.out.println("Person: " + p2.getName() + " " + p2.getId() + " " + System.identityHashCode(p2)); 
} 

Query<Student> qS = pm.newQuery(Student.class); 
Collection<Student>c = (Collection<Student>) qS.execute(); 
for (Student s2: c) { 
    System.out.println("Student: " + s2.getName() + " " + s2.getId() + " " + System.identityHashCode(s2)); 
} 
tx.commit(); 

Человек не меняется из примера шаблона:

@PersistenceCapable(detachable="true") 
public class Person { 
    @PrimaryKey 
    Long id; 
    String name; 

    public Person(long id, String name) { 
     this.id = id; 
     this.name = name; 
    } 

    public String getName() { 
     return name; 
    } 

    public Long getId() { 
     return id; 
    } 
} 

Student класс:

@PersistenceCapable(detachable="true") 
public class Student extends Person { 

    public Student(long id, String name) { 
     super(id, name); 
    } 
} 

Я также добавил Student к persistence.xml файла:

<?xml version="1.0" encoding="UTF-8" ?> 
<persistence 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" 
    version="1.0"> 

    <persistence-unit name="MyTest"> 
     <!-- Add all of your model classes here --> 
     <class>mydomain.model.Person</class> 
     <class>mydomain.model.Student</class> 
     <exclude-unlisted-classes /> 
     <properties> 
      <!-- Update these datastore details if different --> 
      <property name="javax.jdo.PersistenceManagerFactoryClass" value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"/> 
      <property name="javax.jdo.option.ConnectionURL" value="jdbc:h2:mem:nucleus"/> 
      <property name="javax.jdo.option.ConnectionDriverName" value="org.h2.Driver"/> 
      <property name="javax.jdo.option.ConnectionUserName" value="sa"/> 
      <property name="javax.jdo.option.ConnectionPassword" value=""/> 

      <property name="datanucleus.schema.autoCreateAll" value="true"/> 
     </properties> 
    </persistence-unit> 

</persistence> 

При запуске программы я получаю следующий результат:

Person: Sarah 1 454305524 
Person: Sarah 1 1536471117 
Person: Pete 0 1961945640 
Person: Pete 0 1898155970 
Student: Pete 0 1898155970 
Student: Sarah 1 1536471117 

Глядя на System.identityHashCode(...), он возвращается в 4 различных экземпляров Java для первого запроса. Я делаю что-то неправильно? Или ожидаемый результат?

EDIT Я только что подтвердил, что DataNucleus 4.1.8 ведет себя так же, как 5.0.0m1

EDIT

Из логфайл:

17:36:21,660 (main) DEBUG [DataNucleus.Query] - JDOQL Query : Compiling "SELECT FROM mydomain.model.Person" 
17:36:21,668 (main) DEBUG [DataNucleus.Query] - JDOQL Query : Compile Time = 8 ms 
17:36:21,668 (main) DEBUG [DataNucleus.Query] - QueryCompilation: 
    [symbols: this type=mydomain.model.Person] 
17:36:21,669 (main) DEBUG [DataNucleus.Query] - JDOQL Query : Compiling "SELECT FROM mydomain.model.Person" for datastore 
17:36:21,697 (main) DEBUG [DataNucleus.Query] - JDOQL Query : Compile Time for datastore = 28 ms 
17:36:21,698 (main) DEBUG [DataNucleus.Query] - SELECT FROM mydomain.model.Person Query compiled to datastore query "SELECT 'mydomain.model.Person ' AS NUCLEUS_TYPE,A0.ID,A0."NAME" FROM PERSON A0 UNION SELECT 'mydomain.model.Student' AS NUCLEUS_TYPE,A0.ID,A0."NAME" FROM PERSON A0" 
17:36:21,698 (main) DEBUG [DataNucleus.Persistence] - ExecutionContext.internalFlush() process started using ordered flush - 2 enlisted objects 
17:36:21,698 (main) DEBUG [DataNucleus.Persistence] - ExecutionContext.internalFlush() process finished 
17:36:21,698 (main) DEBUG [DataNucleus.Connection] - ManagedConnection found in the pool : "org.data[email protected]3c41ed1d [conn=org.datanucleus.store.rdb[email protected]22ff4249, commitOnRelease=false, closeOnRelease=false, closeOnTxnEnd=true]" for key="[email protected]" in factory="ConnectionFactory:tx[[email protected]]" 
17:36:21,698 (main) DEBUG [DataNucleus.Query] - JDOQL Query : Executing "SELECT FROM mydomain.model.Person" ... 
17:36:21,698 (main) DEBUG [DataNucleus.Datastore.Native] - BATCH [INSERT INTO PERSON ("NAME",ID) VALUES (<'Pete'>,<0>); INSERT INTO PERSON ("NAME",ID) VALUES (<'Sarah'>,<1>)] 
17:36:21,699 (main) DEBUG [DataNucleus.Datastore] - Execution Time = 1 ms (number of rows = [1, 1]) on PreparedStatement "[email protected]fc" 
17:36:21,700 (main) DEBUG [DataNucleus.Datastore] - Closing PreparedStatement "org.data[email protected]5939a379" 
17:36:21,701 (main) DEBUG [DataNucleus.Datastore.Native] - SELECT 'mydomain.model.Person ' AS NUCLEUS_TYPE,A0.ID,A0."NAME" FROM PERSON A0 UNION SELECT 'mydomain.model.Student' AS NUCLEUS_TYPE,A0.ID,A0."NAME" FROM PERSON A0 
17:36:21,702 (main) DEBUG [DataNucleus.Datastore.Retrieve] - Execution Time = 1 ms 
17:36:21,705 (main) DEBUG [DataNucleus.Query] - JDOQL Query : Execution Time = 7 ms 
17:36:21,707 (main) DEBUG [DataNucleus.Cache] - Object with id "mydomain.model.Person:1" not found in Level 1 cache [cache size = 2] 
17:36:21,707 (main) DEBUG [DataNucleus.Cache] - Object with id "mydomain.model.Person:1" not found in Level 2 cache 
17:36:21,708 (main) DEBUG [DataNucleus.Cache] - Object "[email protected]" (id="mydomain.model.Person:1") added to Level 1 cache (loadedFlags="[YN]") 
17:36:21,709 (main) DEBUG [DataNucleus.Cache] - Object "[email protected]" (id="1") added to Level 2 cache (fields="[0, 1]", version="") 
17:36:21,711 (main) DEBUG [DataNucleus.Lifecycle] - Object "[email protected]" (id="mydomain.model.Person:1") has a lifecycle change : "HOLLOW"->"P_CLEAN" 
17:36:21,711 (main) DEBUG [DataNucleus.Transaction] - Object "[email protected]" (id="1") enlisted in transactional cache 
17:36:21,712 (main) DEBUG [DataNucleus.Cache] - Object "[email protected]" (id="mydomain.model.Student:1") taken from Level 1 cache (loadedFlags="[YY]") [cache size = 3] 
17:36:21,712 (main) DEBUG [DataNucleus.Cache] - Object "[email protected]" (id="mydomain.model.Person:0") taken from Level 1 cache (loadedFlags="[YY]") [cache size = 3] 
17:36:21,712 (main) DEBUG [DataNucleus.Cache] - Object with id "mydomain.model.Student:0" not found in Level 1 cache [cache size = 3] 
17:36:21,713 (main) DEBUG [DataNucleus.Cache] - Object with id "mydomain.model.Student:0" not found in Level 2 cache 
17:36:21,713 (main) DEBUG [DataNucleus.Cache] - Object "[email protected]" (id="mydomain.model.Student:0") added to Level 1 cache (loadedFlags="[YN]") 
17:36:21,713 (main) DEBUG [DataNucleus.Cache] - Object "[email protected]" (id="0") added to Level 2 cache (fields="[0, 1]", version="") 
17:36:21,713 (main) DEBUG [DataNucleus.Lifecycle] - Object "[email protected]" (id="mydomain.model.Student:0") has a lifecycle change : "HOLLOW"->"P_CLEAN" 
17:36:21,713 (main) DEBUG [DataNucleus.Transaction] - Object "[email protected]" (id="0") enlisted in transactional cache 
17:36:21,713 (main) DEBUG [DataNucleus.Query] - JDOQL Query : Compiling "SELECT FROM mydomain.model.Student" 
17:36:21,713 (main) DEBUG [DataNucleus.Query] - JDOQL Query : Compile Time = 0 ms 
17:36:21,713 (main) DEBUG [DataNucleus.Query] - QueryCompilation: 
    [symbols: this type=mydomain.model.Student] 
17:36:21,713 (main) DEBUG [DataNucleus.Query] - JDOQL Query : Compiling "SELECT FROM mydomain.model.Student" for datastore 
17:36:21,714 (main) DEBUG [DataNucleus.Query] - JDOQL Query : Compile Time for datastore = 1 ms 
17:36:21,714 (main) DEBUG [DataNucleus.Query] - SELECT FROM mydomain.model.Student Query compiled to datastore query "SELECT 'mydomain.model.Student' AS NUCLEUS_TYPE,A0.ID,A0."NAME" FROM PERSON A0" 
17:36:21,714 (main) DEBUG [DataNucleus.Connection] - ManagedConnection found in the pool : "org.data[email protected]3c41ed1d [conn=org.datanucleus.store.rdb[email protected]22ff4249, commitOnRelease=false, closeOnRelease=false, closeOnTxnEnd=true]" for key="[email protected]" in factory="ConnectionFactory:tx[[email protected]]" 
17:36:21,714 (main) DEBUG [DataNucleus.Query] - JDOQL Query : Executing "SELECT FROM mydomain.model.Student" ... 
17:36:21,714 (main) DEBUG [DataNucleus.Datastore] - Closing PreparedStatement "org.data[email protected]6b8ca3c8" 
17:36:21,715 (main) DEBUG [DataNucleus.Datastore.Native] - SELECT 'mydomain.model.Student' AS NUCLEUS_TYPE,A0.ID,A0."NAME" FROM PERSON A0 
17:36:21,715 (main) DEBUG [DataNucleus.Datastore.Retrieve] - Execution Time = 1 ms 
17:36:21,715 (main) DEBUG [DataNucleus.Query] - JDOQL Query : Execution Time = 1 ms 
17:36:21,715 (main) DEBUG [DataNucleus.Cache] - Object "[email protected]" (id="mydomain.model.Student:0") taken from Level 1 cache (loadedFlags="[YY]") [cache size = 4] 
17:36:21,715 (main) DEBUG [DataNucleus.Cache] - Object "[email protected]" (id="mydomain.model.Student:1") taken from Level 1 cache (loadedFlags="[YY]") [cache size = 4] 

Я думаю, что это интересно что запрос Student выполняется в таблице PERSON без дополнительных параметров. Не знаю, как они отображают наследование в базе данных, но если все классы отображаются в одну таблицу, то я бы по крайней мере ожидать один столбец с идентификатором типа:

17:36:21,715 (main) DEBUG [DataNucleus.Datastore.Native] - SELECT 'mydomain.model.Student' AS NUCLEUS_TYPE,A0.ID,A0."NAME" FROM PERSON A0 
+0

Глядя на сгенерированный SQL, можно что-то обнаружить, как и журнал. Может быть, вы не подумали, где они будут храниться (одна таблица?, Две таблицы?) И использование дискриминаторов? –

ответ

1

Вы не указали стратегия наследования и как вы хотите, чтобы механизм персистентности различал классы, разделяющие таблицу. Использовать @Inheritance и @Discriminator согласно these docs. Хотя по умолчанию стратегия наследования будет иметь значение NEW_TABLE для базового класса и SUPERCLASS_TABLE для подкласса, он НЕ будет использовать какой-либо дискриминатор по умолчанию, потому что, возможно, вы не хотели иметь его и никогда не нуждались в разделении того, что хранится в этой таблице

+0

Хорошо, спасибо. На самом деле это очень интересно так косвенно, что упомянутый документ указывает, что стратегия по умолчанию для JDO заключается в возврате экземпляров суперкласса при запросе подкласса. Это немного удивительно ... – TilmannZ

+0

Можете ли вы также объяснить, почему результаты возвращаются дважды в первом запросе? Возможно, я должен задать для этого отдельный вопрос. – TilmannZ

Смежные вопросы