簡體   English   中英

由於內部聯接而不是左聯接,Spring DTO 投影查詢不會返回所有結果

[英]Spring DTO Projection query doesn't return all results due to inner join instead of left join

我正在嘗試對具有訂單列表的實體User進行簡單的 DTO 投影。 投影應僅包含用戶 firstName、lastName 和鏈接表中Order的數量。

User類:

@Entity
@Table(name = "user")
public class User {

    @Column(name = "firstName")
    private String firstName;

    @Column(name = "lastName")
    private String lastName;

    @OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
    private Set<Order> orders;

    // many other fields here

}

Order類:

@Entity
@Table(name = "order")
public class Order {

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;

    // many other fields here

}

然后我有 DTO 對象:

public class UserDetailOrderCountDto {

    private String firstName;
    private String lastName;
    private int orderCount;

    public UserDetailOrderCountDto(String firstName, String lastName, int orderCount) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.orderCount = orderCount;
    }

    // getters, setters, ...

}

最后是帶有查詢的存儲庫:

public interface UserRepository extends JpaRepository<User, Long> {

    @Query("select new a.b.c.UserDetailOrderCountDto(u.firstName, u.lastName, size(u.orders)) from User u group by u.firstName, u.lastName")
    List<UserDetailOrderCountDto> findUsersAndOrderCount();

}

數據庫包含 2 個用戶的 2 個訂單。 有很多用戶沒有任何訂單(我仍然希望以 orderCount 為 0 接收)。 存儲庫中的查詢為 2 個用戶返回 2 個 DTO,每個用戶有 1 個訂單(正確),但跳過沒有訂單的用戶(因為它不是左連接的)。 Hibernate生成的查詢如下:

select user0_.firstName as col_0_0_, user0_.lastName as col_1_0_, count(orders1_.user_id) as col_2_0_ from user user0_, orders orders1_ where user0_.id=orders1_.user_id group by user0_.firstName , user0_.lastName

如何強制 Hibernate 為我提供所有用戶(也稱為左連接,但如果可能,沒有本機查詢)? 或者任何其他方法來獲得我想要的解決方案? 任何幫助表示贊賞。 謝謝你。

更新 1:如果我嘗試強制 Hibernate 使用FetchMode.JOIN連接表,它仍然使用內部連接。

@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
@Fetch(FetchMode.JOIN)
private Set<Order> orders;

然后查詢如下所示:

select user0_.firstName as col_0_0_, user0_.lastName as col_1_0_, count(orders1_.user_id) as col_2_0_ from user user0_ cross join orders orders1_ where user0_.id=orders1_.user_id group by user0_.firstName , user0_.lastName

JPA 查詢

您可以按照下一個方法指示左連接:

  @Query("SELECT new com.your.package.dto.UserDetailOrderCountDto(u.firstName, u.lastName, COUNT(o)) "
          + "FROM User u LEFT JOIN u.orders o group by u.firstName, u.lastName")
  List<UserDetailOrderCountDto> findUsersAndOrderCount();

只需確保將類屬性orderCount更改為 long:

public class UserDetailOrderCountDto {
  private String firstName;
  private String lastName;
  private long orderCount;

  public UserDetail() {
  }

  public UserDetail(String firstName, String lastName, long orderCount) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.orderCount = orderCount;
  }

  // Getters and setters
}

請注意,這適用於您的User類的以下配置:

@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private Set<Order> orders;

使用本機查詢

您可以改用本機查詢,這樣您就可以定義左連接:

@Query(value = "select u.first_name as firstName, u.last_name as lastName, count(o.id) as orderCount from user u left join orders o on u.id = o.user_id  group by u.first_name, u.last_name;"
       , nativeQuery = true)
  List<UserDetailOrderCountDto> findUsersAndOrderCount();

您只需要確保生成的列名稱與 bean 的屬性名稱匹配。

此外,在最新版本的 spring 上,您不需要創建 bean,而是可以定義一個接口,然后 spring 創建一個從接口繼承的 bean:

public interface UserDetailOrderCountDto {
  public String getFirstName();
  public String getLastName();
  public int getOrderCount();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM