InvalidDataAccessApiUsageException:参数值 [...] 与预期类型不匹配 [java.util.UUID (n/a)]
InvalidDataAccessApiUsageException: Parameter value [...] did not match expected type [java.util.UUID (n/a)]
我正在使用 Criteria API 通过过滤器构建命名查询。它适用于正常的字符串比较,但在对 UUID 进行过滤时会抛出以下错误:
org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [67279329-5096-4196-9E73-748B33122CE2] did not match expected type [java.util.UUID (n/a)]; nested exception is java.lang.IllegalArgumentException: Parameter value [67279329-5096-4196-9E73-748B33122CE2] did not match expected type [java.util.UUID (n/a)]
有几个问题解决了这个问题,但 none 个有效,我尝试了以下方法:
- 将
@Column(name = "id", updatable = false, nullable = false)
添加到实体字段
- 将
@Type(type="org.hibernate.type.UUIDCharType")
添加到实体字段
- 将
@Type(type="uuid-char")
添加到实体字段
Foo 实体:
@Entity
//lombok stuff
public class Foo {
@Id
private UUID id;
private String name;
//...
}
SQL 变体:
CREATE TABLE foo
(
id UUID NOT NULL PRIMARY KEY,
name VARCHAR NOT NULL,
...
);
FooController:
@GetMapping(value = "/foo")
public ResponseEntity<List<Foo>> findFoos(@RequestParam Map<String, String> filterArguments) {
FooFilter filter = filterMapper.map(filterArguments);
FooSpecification spec = new FooSpecification(filter);
List<Foo> foos = fooRepo.findAll(spec);
//...
}
Foo规格:
public class FooSpecification extends SpecificationHelper implements Specification<Foo> {
private final FooFilter filter;
public FooSpecification(FooFilter filter) {
this.filter = filter;
}
@Override
public Predicate toPredicate(Root<Foo> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
Predicate predicate = null;
predicate = createIdPredicate(root, filter, criteriaBuilder, predicate);
predicate = createNamePredicate(root, filter, criteriaBuilder, predicate);
// ...
return predicate;
}
private Predicate createIdPredicate(Root<Foo> foo, FooFilter filter, CriteriaBuilder cb, Predicate predicate) {
Predicate returnPredicate = predicate;
if (StringUtils.isNotBlank(filter.getId()))
returnPredicate = addAndPredicate(cb, predicate, cb.like(cb.upper(foo.get("id")), "%" + filter.getId().toUpperCase() + "%"));
return returnPredicate;
}
private Predicate createNamePredicate(Root<Foo> foo, FooFilter filter, CriteriaBuilder cb, Predicate predicate) {
Predicate returnPredicate = predicate;
if (StringUtils.isNotBlank(filter.getName()))
returnPredicate = addAndPredicate(cb, predicate, cb.like(cb.upper(foo.get("name")), "%" + filter.getName().toUpperCase() + "%"));
return returnPredicate;
}
}
addAndPredicate
是一个简单的辅助方法,只使用 criteriaBuilder.and(predicate,newPredicate)
FooFilter
只有字符串字段
我使用标准 API 提供的类型转换解决了这个问题。
之前:
addAndPredicate(..., ..., cb.like(cb.upper(foo.get("id")), ...));
之后:
addAndPredicate(..., ..., cb.like(cb.upper(foo.get("id").as(String.class)), ...));
发件人:https://docs.oracle.com/javaee/6/api/javax/persistence/criteria/Expression.html#as(java.lang.Class)
<X> Expression<X> as(java.lang.Class<X> type)
Perform a typecast upon the expression, returning a new expression
object. This method does not cause type conversion: the runtime type
is not changed. Warning: may result in a runtime failure.
问题是您的 FooFilter
仅包含 String
字段,而您正试图将 String id
与 createIdPredicate()
中的 UUID
对象进行比较。这就是抛出异常的原因。有2个解决方案:
- 要么,您应该按照@tentacle
的建议将createIdPredicate()
中的filter.getId().toUpperCase()
部分替换为UUID.fromString(filter.getId())
- 或者,更改您的
FooFilter
过滤器,使 id
的类型为 java.util.UUID
。
顺便说一下,恕我直言,将 UUIDs
与 like
进行比较并不是一个好主意,因为一个 UUID
永远不会像另一个 UUID
,每个 UUID
对象是唯一的。您的谓词应检查由 FooFilter
传输的 ID 与来自 DB
.
的 ID 是否相等
我刚刚遇到了类似的问题,@edward 的回答对我帮助很大 :)
我更改的一件事是使用 cb.equal
而不是 cb.like
,因为在搜索特定 ID 时 equal
方法似乎更有效。
我做的另一件事是只用 UUID.fromString(uuid_string_param)
解析一次我的过滤器参数,这样我只解析一次参数,而不必将数据库 UUID 字段转换为字符串以获得匹配.
干杯。
我正在使用 Criteria API 通过过滤器构建命名查询。它适用于正常的字符串比较,但在对 UUID 进行过滤时会抛出以下错误:
org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [67279329-5096-4196-9E73-748B33122CE2] did not match expected type [java.util.UUID (n/a)]; nested exception is java.lang.IllegalArgumentException: Parameter value [67279329-5096-4196-9E73-748B33122CE2] did not match expected type [java.util.UUID (n/a)]
有几个问题解决了这个问题,但 none 个有效,我尝试了以下方法:
- 将
@Column(name = "id", updatable = false, nullable = false)
添加到实体字段 - 将
@Type(type="org.hibernate.type.UUIDCharType")
添加到实体字段 - 将
@Type(type="uuid-char")
添加到实体字段
Foo 实体:
@Entity
//lombok stuff
public class Foo {
@Id
private UUID id;
private String name;
//...
}
SQL 变体:
CREATE TABLE foo
(
id UUID NOT NULL PRIMARY KEY,
name VARCHAR NOT NULL,
...
);
FooController:
@GetMapping(value = "/foo")
public ResponseEntity<List<Foo>> findFoos(@RequestParam Map<String, String> filterArguments) {
FooFilter filter = filterMapper.map(filterArguments);
FooSpecification spec = new FooSpecification(filter);
List<Foo> foos = fooRepo.findAll(spec);
//...
}
Foo规格:
public class FooSpecification extends SpecificationHelper implements Specification<Foo> {
private final FooFilter filter;
public FooSpecification(FooFilter filter) {
this.filter = filter;
}
@Override
public Predicate toPredicate(Root<Foo> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
Predicate predicate = null;
predicate = createIdPredicate(root, filter, criteriaBuilder, predicate);
predicate = createNamePredicate(root, filter, criteriaBuilder, predicate);
// ...
return predicate;
}
private Predicate createIdPredicate(Root<Foo> foo, FooFilter filter, CriteriaBuilder cb, Predicate predicate) {
Predicate returnPredicate = predicate;
if (StringUtils.isNotBlank(filter.getId()))
returnPredicate = addAndPredicate(cb, predicate, cb.like(cb.upper(foo.get("id")), "%" + filter.getId().toUpperCase() + "%"));
return returnPredicate;
}
private Predicate createNamePredicate(Root<Foo> foo, FooFilter filter, CriteriaBuilder cb, Predicate predicate) {
Predicate returnPredicate = predicate;
if (StringUtils.isNotBlank(filter.getName()))
returnPredicate = addAndPredicate(cb, predicate, cb.like(cb.upper(foo.get("name")), "%" + filter.getName().toUpperCase() + "%"));
return returnPredicate;
}
}
addAndPredicate
是一个简单的辅助方法,只使用 criteriaBuilder.and(predicate,newPredicate)
FooFilter
只有字符串字段
我使用标准 API 提供的类型转换解决了这个问题。
之前:
addAndPredicate(..., ..., cb.like(cb.upper(foo.get("id")), ...));
之后:
addAndPredicate(..., ..., cb.like(cb.upper(foo.get("id").as(String.class)), ...));
发件人:https://docs.oracle.com/javaee/6/api/javax/persistence/criteria/Expression.html#as(java.lang.Class)
<X> Expression<X> as(java.lang.Class<X> type)
Perform a typecast upon the expression, returning a new expression object. This method does not cause type conversion: the runtime type is not changed. Warning: may result in a runtime failure.
问题是您的 FooFilter
仅包含 String
字段,而您正试图将 String id
与 createIdPredicate()
中的 UUID
对象进行比较。这就是抛出异常的原因。有2个解决方案:
- 要么,您应该按照@tentacle 的建议将
- 或者,更改您的
FooFilter
过滤器,使id
的类型为java.util.UUID
。
createIdPredicate()
中的filter.getId().toUpperCase()
部分替换为UUID.fromString(filter.getId())
顺便说一下,恕我直言,将 UUIDs
与 like
进行比较并不是一个好主意,因为一个 UUID
永远不会像另一个 UUID
,每个 UUID
对象是唯一的。您的谓词应检查由 FooFilter
传输的 ID 与来自 DB
.
我刚刚遇到了类似的问题,@edward 的回答对我帮助很大 :)
我更改的一件事是使用 cb.equal
而不是 cb.like
,因为在搜索特定 ID 时 equal
方法似乎更有效。
我做的另一件事是只用 UUID.fromString(uuid_string_param)
解析一次我的过滤器参数,这样我只解析一次参数,而不必将数据库 UUID 字段转换为字符串以获得匹配.
干杯。