在开发的过程中,有一个这样的需求,统计出top10,怎么实现
不好的做法:使用list,循环取出统计数据名称和统计结果,然后放入map中
好的做法:使用了Projection变得很简单
---------------------------------------------------------------------------------------------------------
AlertRepository.java
@Query(value = "select alertResult.count as statisticResult,alertResult.name as statisticsName from(select count(1) count,name from alert where DATA_STATUS='1' GROUP BY name order by count desc)alertResult\n" + "where rownum <= :top",nativeQuery = true) public List<AlertProjection> queryTop10AlertGroupByName(@Param("top")int top);
AlertProjection.java 是一个接口
public interface AlertProjection { String getStatisticsName(); String getStatisticResult(); }
Projections的优点
翻译:在Spring Data Repository的查询方法中通常返回的是domain model。但是有的时候可能因为不同的原因需要改变model的视图,学会了projection就可以很方便地制定视图。
比如下面的模型中,人有名字和地址属性,不希望暴露人的地址,在获取属性时只希望得到名字。
属性说明:
id:主键
firstName 和lastName是数据属性
address 连接到另外一个领域对象
@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;
…
}
Person对应的Repository如下:
interface PersonRepository extends CrudRepository<Person, Long> {
Person findPersonByFirstName(String firstName);
}
Spring data会返回领域对象的所有属性。如果要检索address,可以为其定义如下的Repository
interface AddressRepository extends CrudRepository<Address, Long> {}
这样使用PersonRepository时会返回整个的Person对象,使用AddessRepository则只会返回address。
如果不想暴露address的详细信息,怎么办?
这时候就可以为repository的使用者定义一个或者多个projection,projection内容如下:
NoAddresses.java
interface NoAddresses {
String getFirstName();
String getLastName();
}
注意:
1 projection是一个声明式的接口
2 包含要导出属性的getter,firstName属性的getter写成getFirstName,这样Spring Data框架才能根据约定正确取得属性
如下,在返回值中使用定义好的projection NoAddresses,就会只返回名称,不会返回地址。
interface PersonRepository extends CrudRepository<Person, Long> {
NoAddresses findByFirstName(String firstName);
}