【问题标题】:Spring Data JPA Query with Projection and List creates invalid SQL带有投影和列表的 Spring Data JPA 查询创建无效的 SQL
【发布时间】:2018-04-10 18:15:59
【问题描述】:

我正在尝试使用 JPA 查询和投影仅检索特定部分的数据。这是查询:

@Repository
public interface CompanyRepository extends CrudRepository<Company, Integer> {
    @Query("select co.companyID as companyid, co.companyName as companyname, co.companyAbbr as companyabbr, co.flags as flags from Company co order by companyName asc")
    List<CompanyWithFlags> getAllCompaniesWithFlags();
}

这是投影:

public interface CompanyWithFlags {
    Integer getCompanyid();
    String getCompanyname();
    String getCompanyabbr();
    List<CompanyFlag> getFlags();
}

这是公司实体:

@Entity
@Table(name="companies.companies")
public class Company implements Serializable {
    private static final long serialVersionUID = 1L;

    private int companyID;
    private String companyName;
    private String companyAbbr;
    ...
    private List<CompanyFlag> flags = new ArrayList<>();

    public Company() {}

    @Id
    @Column(name="pk_companyid")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @JsonView(View.AllCompaniesView.class)
    public int getCompanyID() {
        return companyID;
    }

    public void setCompanyID(int companyID) {
        this.companyID = companyID;
    }

    @Column(name="companyname", columnDefinition="VARCHAR(72)")
    @JsonView(View.AllCompaniesView.class)
    public String getCompanyName() {
        return companyName;
    }

    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }

    @Column(name="companyabbr", columnDefinition="VARCHAR(8)")
    @JsonView(View.AllCompaniesView.class)
    public String getCompanyAbbr() {
        return companyAbbr;
    }

    public void setCompanyAbbr(String companyAbbr) {
        this.companyAbbr = companyAbbr;
    }

    ...

    @ManyToMany(fetch=FetchType.LAZY)
    @JoinTable(name="companies.co_flags",
               joinColumns = @JoinColumn(name="fk_companyid", referencedColumnName="pk_companyid"),
               inverseJoinColumns = @JoinColumn(name="fk_flagid", referencedColumnName="pk_flagid"))
    @JsonView(View.AllCompaniesView.class)
    public List<CompanyFlag> getFlags() {
        return flags;
    }

    public void setFlags(List<CompanyFlag> flags) {
        this.flags = flags;
    }
}

如果我将CompanyFlag 排除在查询和投影之外,一切正常。如果我不编写查询,而是使用:

List<CompanyWithFlags> findAllByOrderByCompanyNameAsc();

然后我根据需要获取数据,但还会生成很长的其他(不必要的)查询列表。

事实上,hibernate (5.2.14) 会生成这个查询:

select 
  company0_.pk_companyid as col_0_0_, 
  company0_.companyname as col_1_0_, 
  company0_.companyabbr as col_2_0_, 
  . as col_3_0_, 
  companyfla2_.pk_flagid as pk_flagi1_9_, 
  companyfla2_.fk_categoryid as fk_categ3_9_, 
  companyfla2_.flagname as flagname2_9_ 
from companies.companies company0_ 
inner join companies.co_flags flags1_ on company0_.pk_companyid=flags1_.fk_companyid 
inner join companies.config_flags companyfla2_ on flags1_.fk_flagid=companyfla2_.pk_flagid 
order by companyName asc

很明显,问题出在. as col_3_0_,但我不知道为什么会生成它或如何摆脱它。谁能解释为什么hibernate要添加它以及我可以在存储库中做些什么来以有效的方式获得所需的数据?谢谢!

【问题讨论】:

    标签: mysql hibernate spring-data-jpa


    【解决方案1】:

    这似乎是 Spring Data JPA 中的一个错误 - 请参阅我的报告:DATAJPA-1299

    要解决此问题,请尝试使用带有 'distinct' 的查询方法,如下所示:

    @EntityGraph(attributePaths = "flags")
    List<CompanyWithFlags> findDistinctAllByOrderByCompanyNameAsc();
    

    【讨论】:

    • 感谢您的建议。不幸的是,它仍然产生了一大堆与公司实体中其他属性相关的额外查询。
    【解决方案2】:

    我终于能够找到一个有效的查询,虽然不像我预期的那样。这是查询:

    @Query("select co.companyID as companyid, co.companyName as companyname, co.companyAbbr as companyabbr, fl as flags from Company co left join co.flags fl order by companyName asc")
    List<CompanyWithFlags> getAllCompaniesWithFlags();
    

    我想要/期待格式如下的结果:

    companyid: 1,
    companyabbr: "ABC",
    companyname: "Alpha Beta Company",
    flags: [
      {
        flagID: 1,
        flagName: "Flag 1"
      },
      {
        flagID: 2,
        flagName: "Flag 2"
      }
    ]
    

    但是,查询会产生如下结果:

    companyid: 1,
    companyabbr: "ABC",
    companyname: "Alpha Beta Company",
    flags: [
      {
        flagID: 1,
        flagName: "Flag 1"
      }
    ],
    companyid: 1,
    companyabbr: "ABC",
    companyname: "Alpha Beta Company",
    flags: [
      {
        flagID: 2,
        flagName: "Flag 2"
      }
    ]
    

    我在前端使用 Angular,它能够正确读取它以实现我想要的最终结果,所以这个查询对我有用。它在 Hibernate 中产生最少的 SQL 查询。

    【讨论】:

      猜你喜欢
      • 2022-12-02
      • 2021-06-01
      • 2020-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-10
      • 1970-01-01
      相关资源
      最近更新 更多