我有一个搜索API,可以抽象地搜索持久化方案中定义的引用实体的属性。 例如,我有像这样的实体:
@Entity
public class EntityA {
@Column
private String someProperty;
@Column
private EntityB someReference;
}
@Entity
public class EntityB {
@Column
private String someProperty;
@Column
private Set<EntityC> someReferences;
}
@Entity
public class EntityC {
@Column
private String someProperty;
}
使用这些实体时,我可以遍历路径(例如,当我的根实体为EntityA且我确定用户在搜索字符串字段时):
private Expression<String> getExpression(Root<T> root, String fieldName) {
String[] propertySplit = fieldName.split("\\.");
Path<String> path = null;
for (String property : propertySplit) {
if (path == null) {
path = root.get(property);
continue;
}
path = path.get(property);
}
return path;
}
假设当前 为 EntityA,我可以这样调用 getExpression 方法:
[...]
criteriaBuilder.equal(getExpression(entityARoot, "someProperty"), "myValue");
[...]
我也可以调用引用:
[...]
criteriaBuilder.equal(getExpression(entityARoot, "someReference.someProperty"), "myValue");
[...]
但是当路径遇到集合类型时,这种方法就不起作用了,但我想做类似于这样的事情:
[...]
criteriaBuilder.equal(getExpression(entityARoot, "someReference.someReferences.someProperty"), "myValue");
[...]
我遇到了以下异常:
java.lang.IllegalStateException: Illegal attempt to dereference path source [null.someReferences] of basic type
我知道一定有方法可以做到这一点,因为Spring Data也可以使用Repository中的方法名称实现。我的目标是创建一个函数,可以遍历任何未知对象,只要我检查的最终属性是我所知道的类型,那么每次我都知道该标准是应该比较字符串、整数、布尔值、日期等。
root.join(property)
或path.join(property)
吗?请参考 https://dev59.com/qlQJ5IYBdhLWcg3wdVkW。 - JMSillaget(property)
返回的对象转换为一个包含join()
方法的接口,并调用它。我认为最好的检查方法是通过调试并观察get(property)
返回的实际类别来进行。join()
方法在From<>
接口中声明,而Root<>
继承自它:https://docs.oracle.com/javaee/7/api/javax/persistence/criteria/From.html。 - JMSillaClass rootClass = ((RootImpl) root).getEntityType().getJavaType();
,通过反射,您可以找到有关root.property字段的信息,并相应地采取行动:如果root.property是叶子,则只需创建谓词;而如果您处于root.property1.property2.property3的情况下,并且发现property1是@Entity,则加入实体并在路径joinProperty1.property2.property3的其余部分上应用相同的机制。 - tremendous7