JPA OneTomany收集具有继承限制的特定子类



我正在与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。

我正在努力弄清楚如何创建将考虑到这一点而不加入不需要的子类的查询。子类具有"类型"属性,该属性可以识别不同的子类(如果有帮助,请参见A)。

让我知道您是否需要更多信息,

谢谢!

编辑:

我尝试采用建议的方法,这是结果:

  1. 按类型查询。

这不起作用。懒惰的提取仍然查询我列表中的所有对象,无论我选择哪种获取策略(懒惰或渴望)。代码:

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. 如果要直接选择实体层次结构,则可以使用以下方式限制要返回的类型:

     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)
    

我在此处使用了LEFt JOIN,因为如果数据库中没有关联的elements,您将不会获得Holder的任何内容,否则。

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

最新更新