Java Spring Data JPA Projection 从数据库中选择的字段
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/40194614/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring Data JPA Projection selected fields from the DB
提问by arammal
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,
谢谢,
回答by Andrés Cuadros Suárez
If you want use the annotation @Querywith Spring Data Projections you have to use field alias and you need to make sure you alias the projects matching the projection fields. The following code should work for question 1:
如果要将注解@Query与 Spring Data Projections 一起使用,则必须使用字段别名,并且需要确保为与投影字段匹配的项目设置别名。以下代码应该适用于问题 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. whenever is possible:
您可以使用的另一种替代方法是使用Property Expressions定义您的查询。只要有可能:
interface PersonRepository extends CrudRepository<Person, Long> {
List<PersonLimited> findByFirstName(String firstName);
}