这篇文章涉及 Hibernate。
将 @SqlResultSetMapping 和 @NamedNativeQuery(或 @NamedQuery)放入 @Entity 的建议类定义不够优雅,显然没有遵循关注点分离原则。
更合适的解决方案是使用 @MappedSuperclass 注释,如下所示:
SingerExtended.java(类必须是abstract):
package pl.music.model.singer.extended;
import javax.persistence.ColumnResult;
import javax.persistence.ConstructorResult;
import javax.persistence.MappedSuperclass;
import javax.persistence.NamedNativeQueries;
import javax.persistence.NamedNativeQuery;
import javax.persistence.SqlResultSetMapping;
@MappedSuperclass
@SqlResultSetMapping( // @formatter:off
name = "SingerExtendedMapping",
classes = @ConstructorResult(
targetClass = SingerExtendedDTO.class,
columns = {
@ColumnResult(name = "singer_id", type = Long.class),
@ColumnResult(name = "first_name"),
@ColumnResult(name = "last_name"),
@ColumnResult(name = "count_albums", type = Long.class)
}
)
)
@NamedNativeQueries({
@NamedNativeQuery(
name = "SingerExtendedAsc",
query = "select"
+ " singer.singer_id,"
+ " singer.first_name,"
+ " singer.last_name,"
+ " (select count(*) from album where album.singer_id = singer.singer_id) as count_albums"
+ " from singer"
+ " group by singer.singer_id"
+ " order by last_name collate :collation asc, first_name collate :collation asc",
resultSetMapping = "SingerExtendedMapping"
)
}) // @formatter:on
public abstract class SingerExtended {
}
然后是DAO类SingerExtendedDAO.java:
package pl.music.model.singer.extended;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class SingerExtendedDAO {
@PersistenceContext
EntityManager entityManager;
@Autowired
private String collation;
public List<SingerExtendedDTO> getAll(Integer page, Integer count) {
TypedQuery<SingerExtendedDTO> query = entityManager.createNamedQuery("SingerExtendedAsc", SingerExtendedDTO.class);
query.setParameter("collation", collation);
if ((count != null) && (count.intValue() > 0)) {
query.setMaxResults(count.intValue());
if ((page != null) && (page.intValue() >= 0)) {
query.setFirstResult(count.intValue() * page.intValue());
}
}
List<SingerExtendedDTO> singerExtendedDTOs = query.getResultList();
return singerExtendedDTOs;
}
}
最后是 DTO 类 SingerExtendedDTO.java(您必须提供“完整”构造函数):
package pl.music.model.singer.extended;
public class SingerExtendedDTO {
private Long singerId;
private String firstName;
private String lastName;
private Long countAlbums;
// IMPORTANT: this constructor must be defined !!!
public SingerExtendedDTO(Long singerId, String firstName, String lastName, Long countAlbums) {
this.singerId = singerId;
this.firstName = firstName;
this.lastName = lastName;
this.countAlbums = countAlbums;
}
... getters & setters ...
}
如果按照上面介绍的方式将所有这些放在一起,我们就会得到一个适当的解决方案:
- 一切都在一个包中,
- 查询声明不会污染任何无关实体,
- 保留关注点分离(分离查询+映射、DAO 和 DTO)。