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)]
_
この問題に対処するいくつかの質問がありますが、どれもうまくいかなかったので、以下を試しました:
@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);
//...
}
_
FooSpecification:
_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
には文字列フィールドしかありません
Criteria 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)
式に対して型キャストを実行し、新しい式オブジェクトを返します。このメソッドは型変換を引き起こしません。ランタイム型は変更されません。警告:ランタイムエラーが発生する可能性があります。