具有对特定子类

时间:2016-06-22 16:26:02

标签: java hibernate jpa inheritance one-to-many

我正在玩hibernate + JPA,我正在尝试完成查询以限制集合中的结果。目标是将查询限制为继承级别,因此不会连接所有表。

我的代码:

    @Entity
    public static class Holder {

        @Id
        String holderId = UUID.randomUUID().toString();

        @OneToMany(cascade=CascadeType.ALL)
        @JoinColumn(name="subclassID")
        List<A> elements;
    }

    @Entity
    @Inheritance(strategy=InheritanceType.JOINED)
    public static class A {

        @Id
        String pkey = UUID.randomUUID().toString();

        String type = "a";

        String subclassID;
        @Override
        public String toString() {
            return "Class A, pkey: " + pkey + " Subclass " + subclassID;
        }
    }

    @Entity
    public static class B extends A {

        String test;

        String type = "b";

        @Override
        public String toString() {
            return "Class B, pkey: " + pkey + " Subclass " + subclassID + " Test: " + test;
        }
    }

    @Entity
    public static class C extends A {
        String ello;

        String type = "c";

        @Override
        public String toString() {
            return "Class C, pkey: " + pkey + " Subclass " + subclassID + " ello: " + ello;
        }
    }

现在,使用此代码:

        EntityManager em = createEntityManagerFactory.createEntityManager();

        em.getTransaction().begin();
        Holder h = new Holder();
        h.holderId = "hid";
        h.elements = new ArrayList<>();
        A e = new A();
        e.subclassID = h.holderId;
        h.elements.add(e);

        B b = new B();
        b.subclassID = h.holderId;
        b.test = "test";
        h.elements.add(b);

        C c = new C();
        c.subclassID = h.holderId;
        c.ello = "Ello";
        h.elements.add(c);

        em.persist(h);
        em.getTransaction().commit();

        em.getTransaction().begin();
        Holder find = em.find(Holder.class, "hid");
        em.getTransaction().commit();


        find.elements.forEach(x -> System.err.println(x));

它将打印所有子类并正确获取它们。所以我明白了:

Class A, pkey: 5074ec45-5917-47aa-9ce7-b904fbb78a54 Subclass hid
Class B, pkey: a8afc689-1314-4253-8d20-4751526c0d00 Subclass hid Test: test
Class C, pkey: f57137cc-32fd-473c-8310-0f83c7dad2ed Subclass hid ello: Ello

由于我有一个联合策略,因此必须加入所有子类表,这些表在某些时候可能会非常多。

现在大多数时候我都知道我要查询的是哪种子类,例如我只想要A,或A和B,但不是C.

我正在努力弄清楚如何创建一个将考虑到这一点的查询,而不是加入不需要的子类。子类有一个&#34;类型&#34;标识不同子类的属性(参见A),如果有帮助的话。

如果您需要更多信息,请告诉我,

谢谢!

编辑:

我尝试了建议的方法,结果如下:

  1. 按类型查询。
  2. 这不起作用。无论我选择什么提取策略(懒惰或渴望),延迟提取仍会查询列表中的所有对象。代码:

    Query xx = em.createQuery("SELECT h FROM TestApp$Holder h LEFT JOIN h.elements e where TYPE(e) = TestApp$B", Holder.class);
    
        System.out.println(" -- -- -- -- -");
        List<Holder> resultList = xx.getResultList();
        resultList.stream().forEach(x -> {
            x.elements.forEach(x2 -> System.err.println(x2));
        });
    

    输出:

    14:17:44.466 [main] DEBUG org.hibernate.SQL - select testapp_ho0_.holderId as holderId1_0_ from holder testapp_ho0_ left outer join TestApp$A elements1_ on testapp_ho0_.holderId=elements1_.subclassID left outer join TestApp$B elements1_1_ on elements1_.pkey=elements1_1_.pkey left outer join TestApp$C elements1_2_ on elements1_.pkey=elements1_2_.pkey where case when elements1_1_.pkey is not null then 1 when elements1_2_.pkey is not null then 2 when elements1_.pkey is not null then 0 end=1
    Hibernate: select testapp_ho0_.holderId as holderId1_0_ from holder testapp_ho0_ left outer join TestApp$A elements1_ on testapp_ho0_.holderId=elements1_.subclassID left outer join TestApp$B elements1_1_ on elements1_.pkey=elements1_1_.pkey left outer join TestApp$C elements1_2_ on elements1_.pkey=elements1_2_.pkey where case when elements1_1_.pkey is not null then 1 when elements1_2_.pkey is not null then 2 when elements1_.pkey is not null then 0 end=1
    14:17:44.468 [main] DEBUG org.hibernate.loader.Loader - Result set row: 0
    14:17:44.469 [main] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[io.test.TestApp$Holder#hid]
    14:17:44.471 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Resolving associations for [io.test.TestApp$Holder#hid]
    14:17:44.472 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Done materializing entity [io.test.TestApp$Holder#hid]
    14:17:44.473 [main] DEBUG o.h.l.c.p.AbstractLoadPlanBasedCollectionInitializer - Loading collection: [io.test.TestApp$Holder.elements#hid]
    14:17:44.473 [main] DEBUG org.hibernate.SQL - select elements0_.subclassID as subclass2_1_0_, elements0_.pkey as pkey1_1_0_, elements0_.pkey as pkey1_1_1_, elements0_.subclassID as subclass2_1_1_, elements0_.type as type3_1_1_, elements0_1_.test as test1_2_1_, elements0_1_.type as type2_2_1_, elements0_2_.ello as ello1_3_1_, elements0_2_.type as type2_3_1_, case when elements0_1_.pkey is not null then 1 when elements0_2_.pkey is not null then 2 when elements0_.pkey is not null then 0 end as clazz_1_ from TestApp$A elements0_ left outer join TestApp$B elements0_1_ on elements0_.pkey=elements0_1_.pkey left outer join TestApp$C elements0_2_ on elements0_.pkey=elements0_2_.pkey where elements0_.subclassID=?
    Hibernate: select elements0_.subclassID as subclass2_1_0_, elements0_.pkey as pkey1_1_0_, elements0_.pkey as pkey1_1_1_, elements0_.subclassID as subclass2_1_1_, elements0_.type as type3_1_1_, elements0_1_.test as test1_2_1_, elements0_1_.type as type2_2_1_, elements0_2_.ello as ello1_3_1_, elements0_2_.type as type2_3_1_, case when elements0_1_.pkey is not null then 1 when elements0_2_.pkey is not null then 2 when elements0_.pkey is not null then 0 end as clazz_1_ from TestApp$A elements0_ left outer join TestApp$B elements0_1_ on elements0_.pkey=elements0_1_.pkey left outer join TestApp$C elements0_2_ on elements0_.pkey=elements0_2_.pkey where elements0_.subclassID=?
    14:17:44.475 [main] DEBUG o.h.l.p.e.p.i.ResultSetProcessorImpl - Preparing collection intializer : [io.test.TestApp$Holder.elements#hid]
    14:17:44.477 [main] DEBUG o.h.l.p.e.p.i.ResultSetProcessorImpl - Starting ResultSet row #0
    14:17:44.478 [main] DEBUG o.h.l.p.e.p.i.CollectionReferenceInitializerImpl - Found row of collection: [io.test.TestApp$Holder.elements#hid]
    14:17:44.479 [main] DEBUG o.h.l.p.e.p.i.ResultSetProcessorImpl - Starting ResultSet row #1
    14:17:44.479 [main] DEBUG o.h.l.p.e.p.i.CollectionReferenceInitializerImpl - Found row of collection: [io.test.TestApp$Holder.elements#hid]
    14:17:44.480 [main] DEBUG o.h.l.p.e.p.i.ResultSetProcessorImpl - Starting ResultSet row #2
    14:17:44.480 [main] DEBUG o.h.l.p.e.p.i.CollectionReferenceInitializerImpl - Found row of collection: [io.test.TestApp$Holder.elements#hid]
    14:17:44.480 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Resolving associations for [io.test.TestApp$A#c9b6a82a-eed7-48f5-824e-c591537a6be6]
    14:17:44.480 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Done materializing entity [io.test.TestApp$A#c9b6a82a-eed7-48f5-824e-c591537a6be6]
    14:17:44.480 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Resolving associations for [io.test.TestApp$B#c73dd9ae-9e4e-483e-96cc-4ab802f5dc59]
    14:17:44.480 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Done materializing entity [io.test.TestApp$B#c73dd9ae-9e4e-483e-96cc-4ab802f5dc59]
    14:17:44.480 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Resolving associations for [io.test.TestApp$C#729f2528-18f5-44da-9dca-2b399b66e183]
    14:17:44.480 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Done materializing entity [io.test.TestApp$C#729f2528-18f5-44da-9dca-2b399b66e183]
    14:17:44.480 [main] DEBUG o.h.e.l.i.CollectionLoadContext - 1 collections were found in result set for role: io.test.TestApp$Holder.elements
    14:17:44.481 [main] DEBUG o.h.e.l.i.CollectionLoadContext - Collection fully initialized: [io.test.TestApp$Holder.elements#hid]
    14:17:44.481 [main] DEBUG o.h.e.l.i.CollectionLoadContext - 1 collections initialized for role: io.test.TestApp$Holder.elements
    14:17:44.481 [main] DEBUG o.h.r.j.i.ResourceRegistryStandardImpl - HHH000387: ResultSet's statement was not registered
    14:17:44.481 [main] DEBUG o.h.l.c.p.AbstractLoadPlanBasedCollectionInitializer - Done loading collection
    Class A, pkey: c9b6a82a-eed7-48f5-824e-c591537a6be6 Subclass hid
    Class B, pkey: c73dd9ae-9e4e-483e-96cc-4ab802f5dc59 Subclass hid Test: test
    Class C, pkey: 729f2528-18f5-44da-9dca-2b399b66e183 Subclass hid ello: Ello
    
    2. Fetch in query 
    

    在服务工作的哪个位置自动获取查询的工作原理是什么,但它仍然连接所有表,尽管该类型明确地消除了不必要的连接的任何结果。 这看起来像这样:

    Query xx = em.createQuery("SELECT h FROM TestApp$Holder h LEFT JOIN fetch h.elements e where TYPE(e) = TestApp$B", Holder.class);
    
            System.out.println(" -- -- -- -- -");
            List<Holder> resultList = xx.getResultList();
            resultList.stream().forEach(x -> {
                x.elements.forEach(x2 -> System.err.println(x2));
            });
    

    输出:

    14:20:25.063 [main] DEBUG org.hibernate.SQL - select testapp_ho0_.holderId as holderId1_0_0_, elements1_.pkey as pkey1_1_1_, elements1_.subclassID as subclass2_1_1_, elements1_.type as type3_1_1_, elements1_1_.test as test1_2_1_, elements1_1_.type as type2_2_1_, elements1_2_.ello as ello1_3_1_, elements1_2_.type as type2_3_1_, case when elements1_1_.pkey is not null then 1 when elements1_2_.pkey is not null then 2 when elements1_.pkey is not null then 0 end as clazz_1_, elements1_.subclassID as subclass2_1_0__, elements1_.pkey as pkey1_1_0__ from holder testapp_ho0_ left outer join TestApp$A elements1_ on testapp_ho0_.holderId=elements1_.subclassID left outer join TestApp$B elements1_1_ on elements1_.pkey=elements1_1_.pkey left outer join TestApp$C elements1_2_ on elements1_.pkey=elements1_2_.pkey where case when elements1_1_.pkey is not null then 1 when elements1_2_.pkey is not null then 2 when elements1_.pkey is not null then 0 end=1
    Hibernate: select testapp_ho0_.holderId as holderId1_0_0_, elements1_.pkey as pkey1_1_1_, elements1_.subclassID as subclass2_1_1_, elements1_.type as type3_1_1_, elements1_1_.test as test1_2_1_, elements1_1_.type as type2_2_1_, elements1_2_.ello as ello1_3_1_, elements1_2_.type as type2_3_1_, case when elements1_1_.pkey is not null then 1 when elements1_2_.pkey is not null then 2 when elements1_.pkey is not null then 0 end as clazz_1_, elements1_.subclassID as subclass2_1_0__, elements1_.pkey as pkey1_1_0__ from holder testapp_ho0_ left outer join TestApp$A elements1_ on testapp_ho0_.holderId=elements1_.subclassID left outer join TestApp$B elements1_1_ on elements1_.pkey=elements1_1_.pkey left outer join TestApp$C elements1_2_ on elements1_.pkey=elements1_2_.pkey where case when elements1_1_.pkey is not null then 1 when elements1_2_.pkey is not null then 2 when elements1_.pkey is not null then 0 end=1
    14:20:25.066 [main] DEBUG org.hibernate.loader.Loader - Result set row: 0
    14:20:25.067 [main] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[io.test.TestApp$Holder#hid], EntityKey[io.test.TestApp$A#3c5b7de6-1658-49ab-b90b-eacde31276c3]
    14:20:25.071 [main] DEBUG org.hibernate.loader.Loader - Found row of collection: [io.test.TestApp$Holder.elements#hid]
    14:20:25.077 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Resolving associations for [io.test.TestApp$Holder#hid]
    14:20:25.077 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Done materializing entity [io.test.TestApp$Holder#hid]
    14:20:25.077 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Resolving associations for [io.test.TestApp$B#3c5b7de6-1658-49ab-b90b-eacde31276c3]
    14:20:25.077 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Done materializing entity [io.test.TestApp$B#3c5b7de6-1658-49ab-b90b-eacde31276c3]
    14:20:25.077 [main] DEBUG o.h.e.l.i.CollectionLoadContext - 1 collections were found in result set for role: io.test.TestApp$Holder.elements
    14:20:25.077 [main] DEBUG o.h.e.l.i.CollectionLoadContext - Collection fully initialized: [io.test.TestApp$Holder.elements#hid]
    14:20:25.078 [main] DEBUG o.h.e.l.i.CollectionLoadContext - 1 collections initialized for role: io.test.TestApp$Holder.elements
    Class B, pkey: 3c5b7de6-1658-49ab-b90b-eacde31276c3 Subclass hid Test: test
    

1 个答案:

答案 0 :(得分:1)

  1. 如果您直接选择实体层次结构,则可以使用以下内容限制要返回的类型:

     SELECT a FROM A a WHERE TYPE(a) = A OR TYPE(a) = B
    
  2. 我猜你正在寻找这种情况。在这种情况下,以下可能有效(但我没有测试过自己):

    SELECT h FROM Holder h LEFT JOIN h.elements e WHERE TYPE(e) IN (A, B)
    
  3. 我在这里使用LEFt JOIN,因为如果数据库中没有关联的Holder,您将无法获得elements的任何内容,否则。

    注意:在TYPE(e) = B中,B是实体的名称,而不是字符串。