Closed minkukjo closed 5 months ago
Right now, there's no global hook for query hints. You could however introduce functionality on your side to make it work. SimpleJpaRepository
requires a slightly different approach than QuerydslJpaPredicateExecutor
.
For the base repository implementation SimpleJpaRepository
you need to create a subclass of SimpleJpaRepository
and use that one as base repository.
In the second step, you create a wrapper for CrudMethodMetadata
that holds query hints and other details that are evaluated for each query. You would augment CrudMethodMetadata.getComment()
with details from CrudMethodMetadata.getMethod()
. You could also augment CrudMethodMetadata.getQueryHints()
with a custom wrapper.
For QuerydslJpaPredicateExecutor
, you can subclass JpaRepositoryFactory
and override getRepositoryFragments(…)
to hook into CrudMethodMetadata
.
@mp911de Thank you for your kindness answer. I'm going to try to add sub class of SimpleJpaRepository, JpaRepositoryFactory. Have a good day!
@mp911de
Hi, I have a one more question about "wrapper for CrudMethodMetadata
"
I'm using JPA 2.7 version.
I made a subclass of SimpleJpaRepository so I succeeded to change base repository SimpleJpaRepository to CustomJpaRepository that I made.
And then I override setRepositoryMethodMetadata
to apply Custom CrudMethodMetadata.
But CrudMethodMetadata
is always null when I debug setRepositoryMethodMetadata
when spring is about start.
How Can I make wrapper for CrudMethodMetadata
?
@Repository
public class CustomCrudRepository<T, ID> extends SimpleJpaRepository<T, ID> {
public CustomCrudRepository(
JpaEntityInformation<T, ?> entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager);
}
@Autowired
public CustomCrudRepository(Class<T> domainClass, EntityManager em) {
this(JpaEntityInformationSupport.getEntityInformation(domainClass, em), em);
}
@Override
public void setRepositoryMethodMetadata(CrudMethodMetadata crudMethodMetadata) { // <- parameter is always null
CrudMethodMetadata repositoryMethodMetadata = super.getRepositoryMethodMetadata();
repositoryMethodMetadata.getMethod().getName();
if (repositoryMethodMetadata instanceof CustomCrudMethodMetadata) {
System.out.println("True!");
}
if (crudMethodMetadata instanceof CustomCrudMethodMetadata) {
System.out.println("True!");
}
super.setRepositoryMethodMetadata(crudMethodMetadata);
}
}
I copied DefaultCrudMethodMetadata
to make custom CrudMethodMetadata
like below
public class CustomCrudMethodMetadata implements CrudMethodMetadata {
@Nullable
private final LockModeType lockModeType;
private final QueryHints queryHints;
private final QueryHints queryHintsForCount;
private final Optional<EntityGraph> entityGraph;
private final Method method;
CustomCrudMethodMetadata(Method method) {
Assert.notNull(method, "Method must not be null!");
this.lockModeType = findLockModeType(method);
this.queryHints = findQueryHints(method, (it) -> true);
this.queryHintsForCount = findQueryHints(
method, org.springframework.data.jpa.repository.QueryHints::forCounting);
this.entityGraph = findEntityGraph(method);
this.method = method;
}
private static Optional<EntityGraph> findEntityGraph(Method method) {
return Optional.ofNullable(
AnnotatedElementUtils.findMergedAnnotation(method, EntityGraph.class));
}
@Nullable
private static LockModeType findLockModeType(Method method) {
Lock annotation = AnnotatedElementUtils.findMergedAnnotation(method, Lock.class);
return annotation == null ? null : (LockModeType) AnnotationUtils.getValue(annotation);
}
private static QueryHints findQueryHints(Method method,
Predicate<org.springframework.data.jpa.repository.QueryHints> annotationFilter) {
MutableQueryHints queryHints = new MutableQueryHints();
org.springframework.data.jpa.repository.QueryHints queryHintsAnnotation = (org.springframework.data.jpa.repository.QueryHints) AnnotatedElementUtils.findMergedAnnotation(
method, org.springframework.data.jpa.repository.QueryHints.class);
if (queryHintsAnnotation != null && annotationFilter.test(queryHintsAnnotation)) {
QueryHint[] var4 = queryHintsAnnotation.value();
int var5 = var4.length;
for (int var6 = 0; var6 < var5; ++var6) {
QueryHint hint = var4[var6];
queryHints.add(hint.name(), hint.value());
}
}
QueryHint queryHintAnnotation = AnnotationUtils.findAnnotation(method, QueryHint.class);
if (queryHintAnnotation != null) {
queryHints.add(queryHintAnnotation.name(), queryHintAnnotation.value());
}
return queryHints;
}
@Nullable
public LockModeType getLockModeType() {
return this.lockModeType;
}
public QueryHints getQueryHints() {
return this.queryHints;
}
public QueryHints getQueryHintsForCount() {
return this.queryHintsForCount;
}
public Optional<EntityGraph> getEntityGraph() {
return this.entityGraph;
}
public Method getMethod() {
return this.method;
}
}
How Can I customize CrudMethodMetadata
to apply global query hint in SimpleJpaRepository?
Could you give me more hint to achieve my goal that is made global query comment in simpleJpaRepository
I was so appreciated your answer. Thanks a lot!! 😄
I'm using spring boot and spring data jpa 2.7 version for developing our service. I would like to add every jpa query method when jpa makes sql query without any annotation.
In my version, if I want to add query comment in jpa, I have to use like this,
I want to add query comment as "jpa query method name".
When slow query is occurred, our DBA would let us which query is slow.
However, Our service has so many jpa and querydsl queries in our service so we don't know where query is used in our codes.
So we decide to add every query comment in our codes like"/ findByUserId /".
I couldn't find these kind of option in jpa.
I wonder spring data jpa team has a plan that is going to add global query hint in jpa.
I'm so appreciated your services.
Thank you!