学习的文章资料:
在JPA查询中,全部都是默认返回对象的所有属性,若:
- 你只需要对象的几个属性
- 你只不需要对象的某几个属性,剩下的属性全部要
那么,返回对象的全部属性就变成了负担。
解决方案
方案(一) 使用@Query
注解
@Query("select u.name from User u where u.id=?1")
String getNameById(int id);
如果想返回对象,则需要根据自己的需求创建新的对象。
// 对应到表的Entity
@Data
public class User {
private int id;
private String name;
private Integer age;
private String tel;
private String email;
// 根据自己需要创建对应的构造函数
public User(String name, int age) {
this.name = name;
this.age = age;
}
}
那么,可以这样做
@Query("select new User(u.name, u.age) from User u where u.id=?1")
User getNameAndAgeFromId(int id);
以上方式,只适合:只需要对象的几个属性,如果需要的属性过多,那么写在@Query
的语句也会越长,不利于阅读和维护。
方案(二) 使用JPA提供的Projection投影功能
JPA提供了一种声明方式来解决,即声明一个接口类,然后直接使用这个接口类接受返回的数据即可。这个接口发挥了一个类似于“视图”的作用。
import org.springframework.beans.factory.annotation.Value;
// 注意这个@Value注解是用的Spring的注解.
//这里使用的是SpEL的语法,target即原始类型的对象。在Java 8以后的版本,除了使用 //@Value注解,你还可以使用接口的default方法:
public interface UserProjection {
@Value("#{target.name + ' ' + target.email}") // Projection 可以进行字段重组
String getNameAndEmail();
String getName();
String getAge();
// default 方法实例
default String getFullName() {
return getName().concat(" ").concat(getAge());
}
}
然后可以在自定义的Repository里面将这个接口类型做为返回值。
public interface UserRepository extends JpaRepository<User, Integer> {
Collection<UserProjection> findByName(String name);
}
使用DTO
除了使用上面的接口外,我们也可以声明DTO,或者如果是直接作为返回值,我们也可以称之为VO。
class UserOnly {
private final String name, email;
UserOnly(String name, String lastname) {
this.name = name;
this.email = email;
}
String getName() {
return this.name;
}
String getEmail() {
return this.email;
}
// equals(…) and hashCode() implementations
}
使用Lombok 简化代码:
import lombok.Value;
@Value
class UserOnly {
private final String name, email;
}
Lombok提供了对DTO的注解@Value。注意这个注解跟Spring的@Value注解不是同一个,自己引包的时候要注意一下。上面一段代码简化之后是这个样子
动态的Projection
可不可以有很多Projection都用同一个方法,但是返回值根据Projection动态调整呢?我们可以使用泛型来实现这个功能。
public interface UserRepository extends JpaRepository<User, Integer> {
<T>List<T> findByName(String name, Class<T> type);
<T>T findByNameAndEmail(String name, String Email, Class<T> type);
}
调用
void someMethod(UserRepository user) {
User user = user.findByNameAndEmail("Matthews", "test@test.com", User.class);
List<UserOnly> userOnly = user.findByName("Matthews", UserOnly.class);
}
网友评论