按嵌入属性使用 Criteria Builder 进行排序
Sorting with Criteria Builder by embedded attribute
我正在尝试获取按嵌入式栏的时间属性排序的 Foo 的所有实体。我定义了具有嵌入式实体 Bar 的实体 Foo,如下所示:
public class Foo {
...
@Embedded
private Bar bar;
...
}
@Embeddable
public class Bar {
...
@Column(name = "TIME")
private Date time;
...
}
我的存储库中还有静态元模型用于 Foo 和 Bar:
@StaticMetamodel(Foo.class)
public class Foo_{
...
public static volatile SingularAttribute<Foo, String> attribute_;
public static volatile SingularAttribute<Foo, Bar> bar_;
...
}
@StaticMetamodel(Bar.class)
public class Bar_{
public static volatile SingularAttribute<Bar, Date> time_;
}
然后在我的存储库中,我正在使用条件构建器构建查询:
@Repository
public class FooRepositoryImpl implements FooRepository {
...
@Override
public Page<Foo> findAllWithPagingAndFilter(PageRequest pageRequest, String attribute) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Foo> criteriaQuery = criteriaBuilder.createQuery(Foo.class);
Root<Foo> root = criteriaQuery.from(Foo.class);
Predicate attributePredicate= criteriaBuilder.equal(root.get(Foo.attribute_), attribute);
criteriaQuery.where(attributePredicate);
criteriaQuery.orderBy(criteriaBuilder.desc(root.get(Foo_.bar_).get(Bar_.time_)));
TypedQuery<Comment> typedQuery = entityManager.createQuery(criteriaQuery);
typedQuery.setFirstResult((pageRequest.getPageNumber()) * pageRequest.getPageSize());
typedQuery.setMaxResults(pageRequest.getPageSize());
return new PageImpl<>(typedQuery.getResultList(), pageRequest, genericCountWithPredicates(Foo.class, attributePredicate));
}
...
}
以上代码的执行导致 NullPointerException
具有以下堆栈跟踪:
java.lang.NullPointerException: null
at org.hibernate.query.criteria.internal.path.AbstractPathImpl.get(AbstractPathImpl.java:123)
at com.project.server.repositories.impl.FooRepositoryImpl.findAllWithPagingAndFilter(FooRepositoryImpl.java:52)
at com.project.server.repositories.impl.FooRepositoryImpl$$FastClassBySpringCGLIB$a99bbb7.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
FooRepositoryImpl.java:52 指向这一行:
criteriaQuery.orderBy(criteriaBuilder.desc(root.get(Foo_.bar_).get(Bar_.time_)));
我不明白为什么我的代码中 Foo_.bar_ 属性为 null 导致 NPE,你能指出我的错误吗?
好的,我找到了答案,实际上我犯的错误很少:
- 静态模型中的属性应与实体属性同名,因此在两个静态模型中我必须删除
_
后缀
- 由于我正在嵌入其他 class 并使用 Lombok 作为构造函数提供者,而 Bar 没有必需的构造函数,因此嵌入实体在创建时未初始化,导致 class Foo 属性的对象栏为空
我正在尝试获取按嵌入式栏的时间属性排序的 Foo 的所有实体。我定义了具有嵌入式实体 Bar 的实体 Foo,如下所示:
public class Foo {
...
@Embedded
private Bar bar;
...
}
@Embeddable
public class Bar {
...
@Column(name = "TIME")
private Date time;
...
}
我的存储库中还有静态元模型用于 Foo 和 Bar:
@StaticMetamodel(Foo.class)
public class Foo_{
...
public static volatile SingularAttribute<Foo, String> attribute_;
public static volatile SingularAttribute<Foo, Bar> bar_;
...
}
@StaticMetamodel(Bar.class)
public class Bar_{
public static volatile SingularAttribute<Bar, Date> time_;
}
然后在我的存储库中,我正在使用条件构建器构建查询:
@Repository
public class FooRepositoryImpl implements FooRepository {
...
@Override
public Page<Foo> findAllWithPagingAndFilter(PageRequest pageRequest, String attribute) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Foo> criteriaQuery = criteriaBuilder.createQuery(Foo.class);
Root<Foo> root = criteriaQuery.from(Foo.class);
Predicate attributePredicate= criteriaBuilder.equal(root.get(Foo.attribute_), attribute);
criteriaQuery.where(attributePredicate);
criteriaQuery.orderBy(criteriaBuilder.desc(root.get(Foo_.bar_).get(Bar_.time_)));
TypedQuery<Comment> typedQuery = entityManager.createQuery(criteriaQuery);
typedQuery.setFirstResult((pageRequest.getPageNumber()) * pageRequest.getPageSize());
typedQuery.setMaxResults(pageRequest.getPageSize());
return new PageImpl<>(typedQuery.getResultList(), pageRequest, genericCountWithPredicates(Foo.class, attributePredicate));
}
...
}
以上代码的执行导致 NullPointerException
具有以下堆栈跟踪:
java.lang.NullPointerException: null
at org.hibernate.query.criteria.internal.path.AbstractPathImpl.get(AbstractPathImpl.java:123)
at com.project.server.repositories.impl.FooRepositoryImpl.findAllWithPagingAndFilter(FooRepositoryImpl.java:52)
at com.project.server.repositories.impl.FooRepositoryImpl$$FastClassBySpringCGLIB$a99bbb7.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
FooRepositoryImpl.java:52 指向这一行:
criteriaQuery.orderBy(criteriaBuilder.desc(root.get(Foo_.bar_).get(Bar_.time_)));
我不明白为什么我的代码中 Foo_.bar_ 属性为 null 导致 NPE,你能指出我的错误吗?
好的,我找到了答案,实际上我犯的错误很少:
- 静态模型中的属性应与实体属性同名,因此在两个静态模型中我必须删除
_
后缀 - 由于我正在嵌入其他 class 并使用 Lombok 作为构造函数提供者,而 Bar 没有必需的构造函数,因此嵌入实体在创建时未初始化,导致 class Foo 属性的对象栏为空