2016-09-22 8 views
0

Hibernate(5.2.2)の継承戦略 "table per subclass"に問題があります。マッピングと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; 
} 

コレクションTestClassマストからtestsがデータベースからロードされた場合にのみアクセスそれ(遅延ロード)。

TestClassをロードした後にコレクションにアクセスすると、表間に接続がないデカルト製品(LEFT OUTER JOIN)を持つs​​ql-queryが形成されます。

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=?