【发布时间】:2020-03-12 02:45:16
【问题描述】:
考虑 hibernate 的以下 JAVA 模型:
@Entity
@Table
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long id;
@Column
public String firstName;
@Column
public String lastName;
@Column
public Boolean active;
}
以及以下 API 序列化模型(使用 spring boot 休息控制器):
public class PersonVO {
public Long id;
public String fullName;
}
我想要的是:
- 对 Person 应用一些过滤(静态定义)
- 在 PersonVO 应用了一些过滤(从 @RequestParam 获取)
在 C# .NET 中我可以这样:
IQueryable<Person> personsQuery = entityFrameworkDbContext.Persons;
// FIRST POINT - Here i could make some predefined filtering like 'only active', 'from the same city'... at the database model
personsQueryWithPreDefinedFilters = personsQuery.Where(person => person.active == true);
IQueryable<PersonVO> personsProjectedToVO = personsQueryWithPreDefinedFilters.Select(person => new PersonVO()
{
id = person.id,
fullName = person.firstName + " " + person.lastName
});
// SECOND POINT - At this point i could add more filtering based at PersonVO model
if (!String.IsNullOrWhiteSpace(fullNameRequestParameter)) {
personsProjectedToVO = personsProjectedToVO.Where(personVO => personVO.FullName == fullNameRequestParameter);
}
// The generated SQL at database is with both where (before and after projection)
List<PersonVO> personsToReturn = personsProjectedToVO.ToList();
我在 Java 中得到的是:
CriteriaBuilder cb = this.entityManager.getCriteriaBuilder();
CriteriaQuery<PersonVO> cq = cb.createQuery(PersonVO.class);
Root<Person> root = cq.from(Person.class);
// FIRST POINT - Here i could make some predefined filtering like 'only active', 'from the same city'... at the database model
cq.where(cb.equal(root.get(Person_.active), true));
Expression<String> fullName = cb.concat(root.get(Person_.firstName), root.get(Person_.lastName));
cq.select(cb.construct(
PersonVO.class,
root.get(Person_.id),
fullName
));
// SECOND POINT - At this point i could add more filtering based at PersonVO model??? HOW???
if (fullNameRequestParameter != null) {
cq.where(cb.equal(fullName, fullNameRequestParameter));
// i only could use based at the fullName expression used, but could i make a Predicate based only on PersonVO model without knowing or having the expression?
}
我想将“投影到 VO 模型”与应用于它的“where 表达式”分开,但如果使用投影列(如 fullName),则间接应用它。
这在 Java 中可能吗?用什么?标准?查询dsl?溪流? (不一定要坚持 java 示例)
【问题讨论】:
-
使用
Streams 你可以做类似的事情 -personList.stream().filter(p -> p.active).map(p -> new PersonV0(p.id, p.firstName + " " + p.lastName)).filter(pv -> pv.fullName.equals(fullNameRequestParameter)).collect(Collectors.toList());其中Predicate在filter之后使用mapping 是基于PersonV0 -
但是对于流,所有的“查询”都将在数据库生成 sql(使用休眠)时解决,还是只适用于内存中的对象?
-
以上内容仅适用于内存对象。它只是提示您如何处理 Java 中的代码,而不是您应该如何选择使用图片中的 hibernate 来实现它。(这就是为什么评论而不是答案)
-
知道了!感谢@Naman 的评论!我看到这个 ORM speedment.com/stream 可以允许使用
stream()来查询数据库。我认为这可以部分回答我的问题。但我会保持开放,看看是否有人可以用一个具体的例子来回答这个问题(最好使用 hibernate 作为 orm)。 -
您确定实体框架通过 SQL(而不是在内存中)对 FullName 执行过滤器吗?
标签: java hibernate java-stream projection querydsl