简体   繁体   English

Spring Data JPA Projection 从数据库中选择的字段

[英]Spring Data JPA Projection selected fields from the DB

I was testing Spring Data 1.10.4.RELEASE, following the example in Spring Data Docs http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections我正在测试 Spring Data 1.10.4.RELEASE,遵循 Spring Data Docs http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections 中的示例

and I noticed some issues for which I have 2 questions.我注意到一些问题,我有两个问题。

First let's suppose I have these 2 entities:首先让我们假设我有这两个实体:

@Entity
public class Person {

  @Id @GeneratedValue
  private Long id;
  private String firstName, lastName;

  @OneToOne
  private Address address;
}

@Entity
public class Address {

  @Id @GeneratedValue
  private Long id;
  private String street, state, country;
}
  • Question 1:问题 1:

for the following projections:对于以下预测:

interface PersonLimited {  

  String getFirstName(); 

  AddressLimited getAddress();
}

interface AddressLimited {  

  String getCountry(); 
}

when I run findPersonByFirstNameProjectedForLimitedData当我运行findPersonByFirstNameProjectedForLimitedData

interface PersonRepository extends CrudRepository<Person, Long> {

  @Query("select p from Person p where p.firstName = ?1")
  PersonLimited findPersonByFirstNameProjectedForLimitedData(String firstName);
}

it returns exactly what expected :它返回的正是预期的:

{
    firstName: 'Homer',
    address: {
        country: 'USA'
    }
}

now if I look into the generated SQL, this is what I have:现在,如果我查看生成的 SQL,这就是我所拥有的:

SELECT person0_.firstName      AS col_0_0_, 
       address1_.id            AS id1_13_, 
       address1_.street        AS street2_13_, 
       address1_.state         AS state3_13_, 
       address1_.country       AS country4_13_
FROM   person person0_ 
       LEFT OUTER JOIN address address1_ 
                    ON person0_.addressId = address1_.id 
WHERE  person0_.firstName = ?  

The projection for the "Person" entity is selecting only "fistName", which is 100% correct because in the PersonLimited interface I've only defined "getFirstName". “Person”实体的投影仅选择“fistName”,这是 100% 正确的,因为在 PersonLimited 接口中我只定义了“getFirstName”。

But for the "Address" entity, it selects all the fields, which is wrong because in the AddressLimited interface I've only defined "getCountry", It should only select "country".但是对于“Address”实体,它选择了所有字段,这是错误的,因为在 AddressLimited 接口中我只定义了“getCountry”,它应该只选择“country”。

The generated query should be something like:生成的查询应该是这样的:

SELECT person0_.firstName      AS col_0_0_, 
       address1_.country       AS country4_13_
FROM   person person0_ 
       LEFT OUTER JOIN address address1_ 
                    ON person0_.addressId = address1_.id 
WHERE  person0_.firstName = ?  

so the question is, why it is not selecting only the "country" field for the Address "entity"?所以问题是,为什么它不只为地址“实体”选择“国家”字段? why it needs to select all the fields?为什么它需要选择所有字段? is it a bug in Spring?这是Spring的错误吗?

  • Question 2:问题 2:

for the same projection as above,对于与上述相同的投影,

when I run findAllPersonsProjectedForLimitedData当我运行findAllPersonsProjectedForLimitedData

interface PersonRepository extends CrudRepository<Person, Long> {

  @Query("select p from Person p")
  List<PersonLimited> findAllPersonsProjectedForLimitedData();
}

it returns exactly what expected :它返回的正是预期的:

[
     {
        firstName: 'Homer',
        address: {
            country: 'USA'
        }
     },
     {
        firstName: 'Maggie',
        address: {
            country: 'USA'
        }
     }
]

now if I look into the generated SQL, this is what I have:现在,如果我查看生成的 SQL,这就是我所拥有的:

SELECT person0_.id                 AS id1_18_, 
       person0_.firstName          AS firstName2_18_, 
       person0_.lastName           AS lastName3_18_, 
       person0_.addressid          AS company4_18_
FROM   person person0_ 

SELECT address0_.id         AS id1_13_0_, 
       address0_.street     AS street2_13_0_, 
       address0_.state      AS state3_13_0_, 
       address0_.country    AS country4_13_0_
FROM   address address0_ 
WHERE  address0_.id = ? 

here, the projection for both the Person and the Address entities is selecting all the fields which is wrong, it should only select "firstName" and "country".在这里,Person 和 Address 实体的投影选择了所有错误的字段,它应该只选择“firstName”和“country”。

The generated query should be something like:生成的查询应该是这样的:

SELECT person0_.firstName        AS firstName2_18_
FROM   person person0_ 

SELECT address0_.country    AS country4_13_0_
FROM   address address0_ 
WHERE  address0_.id = ? 

is this the normal behavior, shouldn't select only the fields that we need?这是正常行为,不应该只选择我们需要的字段吗?

Thanks,谢谢,

If you want use the annotation @Query with Spring Data Projections you have to use field alias and you need to make sure you alias the projects matching the projection fields.如果要将注解@Query与 Spring Data Projections 一起使用,则必须使用字段别名,并且需要确保为与投影字段匹配的项目设置别名。 The following code should work for question 1:以下代码应该适用于问题 1:

interface PersonRepository extends CrudRepository<Person, Long> {

  @Query("select p.firstName as firstname, p.address as address from Person p where p.firstName = ?1")
  PersonLimited findPersonByFirstNameProjectedForLimitedData(String firstName);
}

Another alternative that you can use is define your queries with Property Expressions .您可以使用的另一种替代方法是使用Property Expressions定义您的查询。 whenever is possible:只要有可能:

interface PersonRepository extends CrudRepository<Person, Long> {

  List<PersonLimited> findByFirstName(String firstName);
}

我遇到了同样的问题,当我将投影从接口更改为 pojo 类时,它正确生成了 SQL。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM