休眠。懒惰装载时的笛卡尔积

时间:2016-09-22 07:25:39

标签: java hibernate

继承策略存在问题"每个子类的表"在Hibernate(5.2.2)。

带有映射的类(未列出gettters和setter):

//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-query访问集合时,表之间没有连接(没有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)
    }
}

我的例子有什么问题?

1 个答案:

答案 0 :(得分:0)

实验上发现问题只发生在Oracle数据库上。在MySQL中,Hibernate会生成正确的sql-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 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=?