【问题标题】:Spring Data JPA DistinctBy projectionsSpring Data JPA DistinctBy 预测
【发布时间】:2020-12-07 04:44:40
【问题描述】:

冬眠者们好! 我有一个关于 DistinctBy 子句如何与 Spring Data's projection

结合使用的问题

假设我有 3 个班级:

public class Task {
  Long id;
  @ManyToOne(fetch = LAZY)
  @JoinColumn(name = "project_id")
  private Project project;
  @OneToOne
  @JoinColumn(name = "contact_id")
  private Contact assigned;
  Boolean deleted;
  // ...
}

public class Contact {
  Long id;
  // ...
}

public class Project { 
  Long id;
  @OneToMany(fetch = LAZY, mappedBy = "project")
  private Set<Task> tasks;
  // ...
}

这些将是我的域类。请注意,Project 确实对 Tasks 有“One2Many”,而 Contact 没有。现在,我有 2 个用于我的预测的接口和带有 2 种方法的基本 TaskRepo:

public interface JustProject {
  Project getProject();
}

public interface JustAssignee {
  Contact getContact();
}

public class TaskRepo extends CrudRepository<Task, Long>, JpaSpecificationExecutor<Task> {
    List<JustAssignee> findDistinctByDeletedFalse();
    List<JustProject> findDistinctByDeletedFalseAndDeletedFalse();
}

它现在对我有用的方式是,findDistinctByDeletedFalse 返回与任务的不同联系人一样多的实例(例如,如果有 10 个任务但只有 3 个联系人,则该方法将仅返回 3 个包含所有3 个不同的联系人)。 findDistinctByDeletedFalseAndDeletedFalse 相同,但在项目级别。

现在我在这里有几个问题,希望能得到一些帮助,以了解它是如何工作的。

  • distinct 子句是否在搜索完成后应用?

    • 我最初的假设是这种行为不会像现在这样起作用。我假设在获取结果之前应用了 distinct 子句,这意味着它将是基于底层任务模型的 DISTINCT,而不是返回的 JustContactJustProject 模型。
  • 有什么办法可以不滥用...AndDeletedFalse 冗余附录?我需要 repo 中的两种方法,但我觉得我必须作弊才能获得结果......

  • ...我做错了吗?我想尽可能优雅地获得“分配给所有任务的所有不同联系人/项目”。我最终想到了这个 distinctby 正是因为我不确定它是如何工作的,并且想试试运气。我真的不认为它会以这种方式工作,但现在我真的很想了解它为什么会这样!

非常感谢

【问题讨论】:

    标签: spring-boot hibernate spring-data-jpa spring-data spring-projections


    【解决方案1】:
    1. DISTINCT 关键字应用于查询,因此它的效果取决于选择列表,而选择列表又由投影控制。因此,如果您的投影中只有project 或只有contact,则DISTINCT 将仅应用于这些值。但是请注意,这在一定程度上依赖于 JPA 规范的边界,如果您看到不同实现的不同行为,我不会感到惊讶。请参阅https://github.com/eclipse-ee4j/jpa-api/issues/189https://github.com/eclipse-ee4j/jpa-api/issues/124,了解针对规范提出的一些相关问题。

    2. 为了区分仅返回值不同的方法,您可以在方法名称中的findBy 之间添加任何附加字符串。例如,您可能希望将方法重命名为 findDistinctContactsByDeletedFalsefindDistinctProjectsByDeletedFalse

    【讨论】:

      【解决方案2】:

      我想这是您使用 Spring Data JPA 可以获得的最佳效果。通过使用dynamic projections 方法,您也许可以只使用一种方法,但我认为这是Blaze-Persistence Entity Views 的完美用例。

      我创建了该库以允许在 JPA 模型和自定义接口或抽象类定义模型之间轻松映射,例如 Spring Data Projections on steroids。这个想法是您按照自己喜欢的方式定义目标结构(域模型),并通过 JPQL 表达式将属性(getter)映射到实体模型。

      使用 Blaze-Persistence Entity-Views 的用例的 DTO 模型可能如下所示:

      @EntityView(Task.class)
      public interface TaskAggregateDto {
          // A synthetic "id" to get a grouping context on object level
          @IdMapping("1")
          int getGroupKey();
      
          Set<ProjectDto> getProjects();
          Set<ContactDto> getContacts();
      
          @EntityView(Project.class)
          interface ProjectDto {
              @IdMapping
              Long getId();
              String getName();
          }
          @EntityView(Contact.class)
          interface ContactDto {
              @IdMapping
              Long getId();
              String getName();
          }
      }
      

      Spring Data 集成让您可以像使用 Spring Data Projections 一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

      public interface TaskRepo extends CrudRepository<Task, Long>, JpaSpecificationExecutor<Task> {
          TaskAggregateDto findOneByDeletedFalse();
      }
      

      【讨论】:

        猜你喜欢
        • 2017-01-19
        • 2017-06-01
        • 2017-05-29
        • 2018-05-10
        • 2021-12-04
        • 1970-01-01
        • 1970-01-01
        • 2017-07-17
        • 1970-01-01
        相关资源
        最近更新 更多