【问题标题】:Join and fetch just some properties not all the collection with JPA and Hibernate使用 JPA 和 Hibernate 加入并获取一些属性,而不是所有集合
【发布时间】:2015-03-26 08:14:12
【问题描述】:

考虑这个查询:

 @Query("select c from Contact c "
         + " join fetch c.abonnements ab ")
 Set<Contact > findServiceNotifContactFtech();

如何在 join 子句中从集合 abonnements 中获取两个或一个属性,因为使用 fetch c.abonnements hibernate 获取我所有的属性,我得到了 abonnements 类型的 30 个属性

【问题讨论】:

    标签: java spring hibernate jpa spring-data


    【解决方案1】:

    如果您只想选择 Abonnement 属性并将它们映射到 DTO(例如 MyDTO),则只需将查询倒置即可:

    @Query("select new my.package.MyDTO(c, ab.prop1, ab.prop2) from Abonnements a join a.contact c")
    Set<MyDTO> findMyDTO();
    

    MyDTO 是这样的:

    public MyDTO {
        private final Contact contact;
        private final String prop1;
        private final String prop2;
    
        public MyDTO(Contact contact, String prop1, String prop2) {
            this.contact= contact;
            this.prop1 = prop1;
            this.prop2 = prop2;
        }
    
        //getters
    }
    

    唯一的问题是每个Abonnnment 子条目会获得更多Contact 条目。

    【讨论】:

    • 这给了我更多的想法,但我不能在我的情况下使用它,因为我不只选择一个集合......还有更多Contact的问题我想在过去处理它案例,但我不能。
    • 但有一个问题 - Concat 是 DTO 对象中的实体。如果我需要获取 Collection 怎么办?
    【解决方案2】:

    如果你觉得这真的很值得,那么请看下面,但请注意关于它很少值得的评论。

    https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/performance.html

    19.1.7。使用惰性属性获取

    Hibernate3 支持对单个属性的惰性获取。这 优化技术也称为获取组。 请注意 这主要是一种营销功能;优化行读取很重要 比优化列读取更重要。然而,只有 加载类的某些属性在极端情况下可能很有用。 例如,当旧表有数百列并且数据 模型无法改进。

    要启用延迟属性加载,请在您的 特定的属性映射:

    延迟属性加载需要构建时字节码检测。如果 你的持久类没有增强,Hibernate 将忽略惰性 属性设置并返回立即获取。

    避免不必要的列读取的另一种方法,至少对于 只读事务,是使用 HQL 的投影功能或 条件查询。这避免了构建时字节码的需要 处理,当然是首选的解决方案。

    您可以使用 fetch all 强制通常急切地获取属性 HQL 中的属性。

    基本上,如文档中所述,可以启用延迟获取属性,但在运行时将被忽略,除非您在构建时使用文档中引用的 Ant 任务“增强”了您的类。如果您的类没有被检测,那么属性级别的延迟加载将被静默忽略。这符合 JPA 规范,该规范不要求支持单个属性的延迟加载:

    http://download.oracle.com/otn-pub/jcp/persistence-2.0-fr-eval-oth-JSpec/persistence-2_0-final-spec.pdf?AuthParam=1423670601_31b0b4beeddadd49047c08d63a9ad933

    见 11.1.16

    LAZY 策略是对持久性提供程序运行时的提示 该数据应在首次访问时延迟获取。这 允许实现急切地获取 LAZY 的数据 已指定策略提示

    【讨论】:

    • Ant Task 有必要吗?我使用 maven,所以我们可以同时使用它们?
    【解决方案3】:

    由于您希望投影适合 DTO 中所需的属性,我建议您给blaze-persistence entity-views 一个机会。你的 DTO 会如下所示:

    @EntityView(Contact.class)
    public interface MyDTO {
    
      @IdMapping
      Integer getId();
    
      // You can have any JPQL expression here
      @Mapping("firstname")
      String getFirstname();
    
      // property name is the default mapping
      String getLastname();
    
      Set<AbonnementDTO> getAbonnements();
    
    }
    
    @EntityView(Abonnement.class)
    public interface AbonnementDTO {
    
      @IdMapping
      Integer getId();
    
      String getProp1();
    
    }
    

    使用站点是这样的

    @Inject
    EntityManager em;
    @Inject
    CriteriaBuilderFactory cbf;
    @Inject
    EntityViewManager evm;
    
    public void test() {
      CriteriaBuilder<Contact> cb = cbf.create(em, Contact.class);
      List<ContactDTO> result = evm.applySetting(EntityViewSetting.create(ContactDTO.class), cb)
          .getResultList();
    }
    

    【讨论】:

      【解决方案4】:

      使用SELECT o.property1, o.property2 FROM EntityA o WHERE ....,结果将是List&lt;Object[2]&gt;,其中数组内容将包含值。

      【讨论】:

      • 但我想要来自 join 子句中实体的属性而不是 from 子句?一样吗?
      • 当然,它们是正交的 - 您在 SELECT 中的内容只需要引用 FROM/JOIN 子句中的内容。
      • 但我有fetch,我必须返回contact
      【解决方案5】:

      您期望从联系人中选择名字,姓氏意味着然后

       @Query("select c.firstname,c.lastname from Contact c "
               + " join fetch c.abonnements ab ")
       Set<Contact > findServiceNotifContactFtech();
      

      【讨论】:

      • 但我想要来自 join 子句中实体的属性而不是 from 子句?一样吗?
      • 但我有fetch,我必须返回contact
      猜你喜欢
      • 2017-10-27
      • 2011-07-03
      • 1970-01-01
      • 1970-01-01
      • 2021-08-03
      • 1970-01-01
      • 2013-12-02
      • 2019-08-24
      • 2020-01-10
      相关资源
      最近更新 更多