2016-09-22 2 views
0

Существует проблема с стратегией наследования «таблица на подкласс» в Hibernate (5.2.2).Hibernate. Декартовы продукты при ленивой загрузке

Классы с картографирования (gettters и сеттеры не перечислены):

//Class with shared fields 
@MappedSuperclass 
public class DBObject { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    protected Integer id; 

    @Column(name = "correctdt") 
    @Temporal(TemporalType.TIMESTAMP) 
    protected Date correctDate; 

    @Override 
    public boolean equals(Object o) { 
     boolean result = false; 
     if (o != null && (o instanceof DBObject)) { 
      DBObject oo = (DBObject) o; 
      if (id != null) { 
       result = id.equals(oo.id); 
      } 
     } 

     return result; 
    } 

    @Override 
    public int hashCode() { 
     return (id != null) ? id.hashCode() : 0; 
    } 
} 


//Class with a collection of items with inheritance. 
@Entity 
@Inheritance(strategy = InheritanceType.JOINED) 
@Table(name = "tmp_test_class") 
public class TestClass extends DBObject implements Serializable{ 
    @OneToMany(mappedBy = "testClass") 
    protected Collection<TestParent> tests = new ArrayList<>(); 
} 


//Parent class 
@Entity 
@Table(name = "tmp_test_parent") 
@Inheritance(strategy = InheritanceType.JOINED) 
public class TestParent extends DBObject implements Serializable{ 
    @Column 
    private String name; 

    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "test_id") 
    protected TestClass testClass; 
} 


//Subclass 
@Entity 
@Table(name = "tmp_test_child1") 
public class TestChild extends TestParent{ 
    @Column 
    private String field1; 
} 

Коллекция tests от TestClass мачте быть загружена из базы данных только тогда, когда доступ к нему (Ленивая загрузка).

При обращении к коллекциям после загрузки TestClass сформированный sql-запрос с декартовым продуктом, где нет связи между таблицами (без LEFT OUTER JOIN).

SELECT tests0_.test_id AS test_id4_2_0_, 
    tests0_.id   AS id1_2_0_, 
    tests0_.id   AS id1_2_1_, 
    tests0_.correctdt AS correctdt2_2_1_, 
    tests0_.name   AS name3_2_1_, 
    tests0_.test_id  AS test_id4_2_1_, 
    tests0_1_.field1  AS field1_0_1_, 
    CASE 
    WHEN tests0_1_.id IS NOT NULL 
    THEN 1 
    WHEN tests0_.id IS NOT NULL 
    THEN 0 
    END AS clazz_1_ 
FROM tmp_test_parent tests0_, 
    tmp_test_child1 tests0_1_ 
WHERE tests0_.test_id=? 

Если я установил FetchType = EAGER, тогда сбор загрузится правильно. Но я бы хотел, чтобы он загружался по требованию, поскольку сбор в большинстве случаев не нужен.

Столы для унаследованных классов:
Таблица tmp_test_parent (3 записи)

"ID" "NAME" "TEST_ID" "CORRECTDT" 
    1  "11"  1  14.09.16 12:31:40 
    2  "22"  1  21.09.16 12:31:46 
    3  "33"  1  21.09.16 12:31:51 

Таблица tmp_test_child (2 записи)

"ID" "FIELD1" "CORRECTDT" 
1   111  21.09.16 12:32:26 
3   333  21.09.16 12:32:28 

Класс для тестирования:

//Class for testing 
public class MainClass { 
    public static void main(String[] args) throws Exception { 

     Session session = HibernateSessionFactory.getSessionFactory().openSession(); 

     //Loading class, that contains collection 
     TestClass test = session.get(TestClass.class, 1); 
     //Loading collection 
     Collection<TestParent> tests = test.getTests(); 

     System.out.println(tests.size()); //Incorrect result (6 entries) 

     //Loading collection directly 
     Collection<TestParent> tests2 = session.createCriteria(TestParent.class) 
       .add(Restrictions.eq("testClass.id", 1)) 
       .list(); 

     System.out.println(tests2.size()); //Correct result (3 entries) 
    } 
} 

Что такое неправильно в моем пример?

ответ

0

Экспериментально выяснилось, что проблема возникает только в базе данных Oracle. В MySQL Hibernate генерируется правильный sql-запрос:

SELECT tests0_.test_id AS test_id4_2_0_, 
    tests0_.id   AS id1_2_0_, 
    tests0_.id   AS id1_2_1_, 
    tests0_.correctdt AS correctd2_2_1_, 
    tests0_.name   AS name3_2_1_, 
    tests0_.test_id  AS test_id4_2_1_, 
    tests0_1_.field1  AS field1_0_1_, 
    CASE 
    WHEN tests0_1_.id IS NOT NULL 
    THEN 1 
    WHEN tests0_.id IS NOT NULL 
    THEN 0 
    END AS clazz_1_ 
FROM tmp_test_parent tests0_ 
LEFT OUTER JOIN tmp_test_child1 tests0_1_ 
ON tests0_.id  =tests0_1_.id 
WHERE tests0_.test_id=? 
Смежные вопросы