DATAJPA-845 - Avoid unnecessary lookups of PersistenceProvider.
To prevent multiple attempts of class loading down stream for multiple lookup calls to fromEntityManager(…) or fromMetamodel(…). We now avoid the repeated lookups of a PersistenceProvider instance by reusing a canonical one created in CreateQueryLookupStrategy. Instead of looking up the PersistenceProvider for every entity again, we now look it up once in the JpaMappingContext for reuse on all JpaPersistentEntity instances. Original pull request: #161.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,6 +22,7 @@ import java.util.Set;
|
||||
import javax.persistence.metamodel.ManagedType;
|
||||
import javax.persistence.metamodel.Metamodel;
|
||||
|
||||
import org.springframework.data.jpa.provider.PersistenceProvider;
|
||||
import org.springframework.data.mapping.context.AbstractMappingContext;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
@@ -34,10 +35,11 @@ import org.springframework.util.Assert;
|
||||
* @author Oliver Gierke
|
||||
* @since 1.3
|
||||
*/
|
||||
public class JpaMetamodelMappingContext extends
|
||||
AbstractMappingContext<JpaPersistentEntityImpl<?>, JpaPersistentProperty> {
|
||||
public class JpaMetamodelMappingContext
|
||||
extends AbstractMappingContext<JpaPersistentEntityImpl<?>, JpaPersistentProperty> {
|
||||
|
||||
private final Set<Metamodel> models;
|
||||
private final PersistenceProvider persistenceProvider;
|
||||
|
||||
/**
|
||||
* Creates a new JPA {@link Metamodel} based {@link MappingContext}.
|
||||
@@ -50,6 +52,7 @@ public class JpaMetamodelMappingContext extends
|
||||
Assert.notEmpty(models, "At least one JPA metamodel must be present!");
|
||||
|
||||
this.models = models;
|
||||
this.persistenceProvider = PersistenceProvider.fromMetamodel(models.iterator().next());
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -58,7 +61,7 @@ public class JpaMetamodelMappingContext extends
|
||||
*/
|
||||
@Override
|
||||
protected <T> JpaPersistentEntityImpl<?> createPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
return new JpaPersistentEntityImpl<T>(typeInformation, getMetamodelFor(typeInformation.getType()));
|
||||
return new JpaPersistentEntityImpl<T>(typeInformation, persistenceProvider);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,10 +17,7 @@ package org.springframework.data.jpa.mapping;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import javax.persistence.metamodel.Metamodel;
|
||||
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.jpa.provider.PersistenceProvider;
|
||||
import org.springframework.data.jpa.provider.ProxyIdAccessor;
|
||||
import org.springframework.data.mapping.IdentifierAccessor;
|
||||
import org.springframework.data.mapping.model.BasicPersistentEntity;
|
||||
@@ -48,14 +45,14 @@ class JpaPersistentEntityImpl<T> extends BasicPersistentEntity<T, JpaPersistentP
|
||||
* Creates a new {@link JpaPersistentEntityImpl} using the given {@link TypeInformation} and {@link Comparator}.
|
||||
*
|
||||
* @param information must not be {@literal null}.
|
||||
* @param metamodel must not be {@literal null}.
|
||||
* @param proxyIdAccessor must not be {@literal null}.
|
||||
*/
|
||||
public JpaPersistentEntityImpl(TypeInformation<T> information, Metamodel metamodel) {
|
||||
public JpaPersistentEntityImpl(TypeInformation<T> information, ProxyIdAccessor proxyIdAccessor) {
|
||||
|
||||
super(information, null);
|
||||
|
||||
Assert.notNull(metamodel, "Metamodel must not be null!");
|
||||
this.proxyIdAccessor = PersistenceProvider.fromMetamodel(metamodel);
|
||||
Assert.notNull(proxyIdAccessor, "ProxyIdAccessor must not be null!");
|
||||
this.proxyIdAccessor = proxyIdAccessor;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -116,7 +113,8 @@ class JpaPersistentEntityImpl<T> extends BasicPersistentEntity<T, JpaPersistentP
|
||||
* @param bean must not be {@literal null}.
|
||||
* @param proxyIdAccessor must not be {@literal null}.
|
||||
*/
|
||||
public JpaProxyAwareIdentifierAccessor(JpaPersistentEntity<?> entity, Object bean, ProxyIdAccessor proxyIdAccessor) {
|
||||
public JpaProxyAwareIdentifierAccessor(JpaPersistentEntity<?> entity, Object bean,
|
||||
ProxyIdAccessor proxyIdAccessor) {
|
||||
|
||||
super(entity, bean);
|
||||
|
||||
@@ -132,8 +130,8 @@ class JpaPersistentEntityImpl<T> extends BasicPersistentEntity<T, JpaPersistentP
|
||||
*/
|
||||
@Override
|
||||
public Object getIdentifier() {
|
||||
return proxyIdAccessor.shouldUseAccessorFor(bean) ? proxyIdAccessor.getIdentifierFrom(bean) : super
|
||||
.getIdentifier();
|
||||
return proxyIdAccessor.shouldUseAccessorFor(bean) ? proxyIdAccessor.getIdentifierFrom(bean)
|
||||
: super.getIdentifier();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2015 the original author or authors.
|
||||
* Copyright 2008-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -44,6 +44,7 @@ import org.hibernate.proxy.HibernateProxy;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ConcurrentReferenceHashMap;
|
||||
|
||||
/**
|
||||
* Enumeration representing persistence providers to be used.
|
||||
@@ -51,7 +52,7 @@ import org.springframework.util.Assert;
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
|
||||
public enum PersistenceProvider implements QueryExtractor,ProxyIdAccessor {
|
||||
|
||||
/**
|
||||
* Hibernate persistence provider.
|
||||
@@ -121,8 +122,8 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
|
||||
/**
|
||||
* EclipseLink persistence provider.
|
||||
*/
|
||||
ECLIPSELINK(Collections.singleton(ECLIPSELINK_ENTITY_MANAGER_INTERFACE), Collections
|
||||
.singleton(ECLIPSELINK_JPA_METAMODEL_TYPE)) {
|
||||
ECLIPSELINK(Collections.singleton(ECLIPSELINK_ENTITY_MANAGER_INTERFACE),
|
||||
Collections.singleton(ECLIPSELINK_JPA_METAMODEL_TYPE)) {
|
||||
|
||||
public String extractQueryString(Query query) {
|
||||
return ((JpaQuery<?>) query).getDatabaseQuery().getJPQLString();
|
||||
@@ -263,6 +264,8 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
|
||||
String OPENJPA_JPA_METAMODEL_TYPE = "org.apache.openjpa.persistence.meta.MetamodelImpl";
|
||||
}
|
||||
|
||||
private static ConcurrentReferenceHashMap<Class<?>, PersistenceProvider> CACHE = new ConcurrentReferenceHashMap<Class<?>, PersistenceProvider>();
|
||||
|
||||
private final Iterable<String> entityManagerClassNames;
|
||||
private final Iterable<String> metamodelClassNames;
|
||||
|
||||
@@ -287,32 +290,65 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
|
||||
*/
|
||||
public static PersistenceProvider fromEntityManager(EntityManager em) {
|
||||
|
||||
Assert.notNull(em);
|
||||
Assert.notNull(em, "EntityManager must not be null!");
|
||||
|
||||
Class<?> entityManagerType = em.getDelegate().getClass();
|
||||
PersistenceProvider cachedProvider = CACHE.get(entityManagerType);
|
||||
|
||||
if (cachedProvider != null) {
|
||||
return cachedProvider;
|
||||
}
|
||||
|
||||
for (PersistenceProvider provider : values()) {
|
||||
for (String entityManagerClassName : provider.entityManagerClassNames) {
|
||||
if (isEntityManagerOfType(em, entityManagerClassName)) {
|
||||
return provider;
|
||||
return cacheAndReturn(entityManagerType, provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GENERIC_JPA;
|
||||
return cacheAndReturn(entityManagerType, GENERIC_JPA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the {@link PersistenceProvider} from the given {@link Metamodel}. If no special one can be determined
|
||||
* {@link #GENERIC_JPA} will be returned.
|
||||
*
|
||||
* @param metamodel must not be {@literal null}.
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public static PersistenceProvider fromMetamodel(Metamodel metamodel) {
|
||||
|
||||
Assert.notNull(metamodel, "Metamodel must not be null!");
|
||||
|
||||
Class<? extends Metamodel> metamodelType = metamodel.getClass();
|
||||
PersistenceProvider cachedProvider = CACHE.get(metamodelType);
|
||||
|
||||
if (cachedProvider != null) {
|
||||
return cachedProvider;
|
||||
}
|
||||
|
||||
for (PersistenceProvider provider : values()) {
|
||||
for (String metamodelClassName : provider.metamodelClassNames) {
|
||||
if (isMetamodelOfType(metamodel, metamodelClassName)) {
|
||||
return provider;
|
||||
return cacheAndReturn(metamodelType, provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GENERIC_JPA;
|
||||
return cacheAndReturn(metamodelType, GENERIC_JPA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches the given {@link PersistenceProvider} for the given source type.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param provider must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private static PersistenceProvider cacheAndReturn(Class<?> type, PersistenceProvider provider) {
|
||||
CACHE.put(type, provider);
|
||||
return provider;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -348,8 +384,8 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
|
||||
}
|
||||
|
||||
public CloseableIterator<Object> executeQueryWithResultStream(Query jpaQuery) {
|
||||
throw new UnsupportedOperationException("Streaming results is not implement for this PersistenceProvider: "
|
||||
+ name());
|
||||
throw new UnsupportedOperationException(
|
||||
"Streaming results is not implement for this PersistenceProvider: " + name());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2013 the original author or authors.
|
||||
* Copyright 2008-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,6 +19,7 @@ import java.lang.reflect.Method;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.springframework.data.jpa.provider.PersistenceProvider;
|
||||
import org.springframework.data.jpa.provider.QueryExtractor;
|
||||
import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.repository.core.NamedQueries;
|
||||
@@ -87,15 +88,19 @@ public final class JpaQueryLookupStrategy {
|
||||
*/
|
||||
private static class CreateQueryLookupStrategy extends AbstractQueryLookupStrategy {
|
||||
|
||||
private final PersistenceProvider persistenceProvider;
|
||||
|
||||
public CreateQueryLookupStrategy(EntityManager em, QueryExtractor extractor) {
|
||||
|
||||
super(em, extractor);
|
||||
this.persistenceProvider = PersistenceProvider.fromEntityManager(em);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em, NamedQueries namedQueries) {
|
||||
|
||||
try {
|
||||
return new PartTreeJpaQuery(method, em);
|
||||
return new PartTreeJpaQuery(method, em, persistenceProvider);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Could not create query metamodel for method %s!", method.toString()), e);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -73,7 +73,6 @@ class ParameterMetadataProvider {
|
||||
* @param provider must not be {@literal null}.
|
||||
*/
|
||||
public ParameterMetadataProvider(CriteriaBuilder builder, Parameters<?, ?> parameters, PersistenceProvider provider) {
|
||||
|
||||
this(builder, null, parameters, provider);
|
||||
}
|
||||
|
||||
@@ -90,9 +89,9 @@ class ParameterMetadataProvider {
|
||||
private ParameterMetadataProvider(CriteriaBuilder builder, Iterator<Object> bindableParameterValues,
|
||||
Parameters<?, ?> parameters, PersistenceProvider provider) {
|
||||
|
||||
Assert.notNull(builder);
|
||||
Assert.notNull(parameters);
|
||||
Assert.notNull(provider);
|
||||
Assert.notNull(builder, "CriteriaBuilder must not be null!");
|
||||
Assert.notNull(parameters, "Parameters must not be null!");
|
||||
Assert.notNull(provider, "PesistenceProvider must not be null!");
|
||||
|
||||
this.builder = builder;
|
||||
this.parameters = parameters.getBindableParameters().iterator();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2014 the original author or authors.
|
||||
* Copyright 2008-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -54,9 +54,10 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
|
||||
* @param factory must not be {@literal null}.
|
||||
* @param em must not be {@literal null}.
|
||||
*/
|
||||
public PartTreeJpaQuery(JpaQueryMethod method, EntityManager em) {
|
||||
public PartTreeJpaQuery(JpaQueryMethod method, EntityManager em, PersistenceProvider persistenceProvider) {
|
||||
|
||||
super(method, em);
|
||||
|
||||
this.em = em;
|
||||
this.domainClass = method.getEntityInformation().getJavaType();
|
||||
this.tree = new PartTree(method.getName(), domainClass);
|
||||
@@ -64,8 +65,8 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
|
||||
|
||||
boolean recreationRequired = parameters.hasDynamicProjection() || parameters.potentiallySortsDynamically();
|
||||
|
||||
this.countQuery = new CountQueryPreparer(recreationRequired);
|
||||
this.query = tree.isCountProjection() ? countQuery : new QueryPreparer(recreationRequired);
|
||||
this.countQuery = new CountQueryPreparer(persistenceProvider, recreationRequired);
|
||||
this.query = tree.isCountProjection() ? countQuery : new QueryPreparer(persistenceProvider, recreationRequired);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -106,10 +107,14 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
|
||||
|
||||
private final CriteriaQuery<?> cachedCriteriaQuery;
|
||||
private final List<ParameterMetadata<?>> expressions;
|
||||
private final PersistenceProvider persistenceProvider;
|
||||
|
||||
public QueryPreparer(boolean recreateQueries) {
|
||||
public QueryPreparer(PersistenceProvider persistenceProvider, boolean recreateQueries) {
|
||||
|
||||
this.persistenceProvider = persistenceProvider;
|
||||
|
||||
JpaQueryCreator creator = createCreator(null, persistenceProvider);
|
||||
|
||||
JpaQueryCreator creator = createCreator(null);
|
||||
this.cachedCriteriaQuery = recreateQueries ? null : creator.createQuery();
|
||||
this.expressions = recreateQueries ? null : creator.getParameterExpressions();
|
||||
}
|
||||
@@ -127,7 +132,7 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
|
||||
ParametersParameterAccessor accessor = new ParametersParameterAccessor(parameters, values);
|
||||
|
||||
if (cachedCriteriaQuery == null || accessor.hasBindableNullValue()) {
|
||||
JpaQueryCreator creator = createCreator(accessor);
|
||||
JpaQueryCreator creator = createCreator(accessor, persistenceProvider);
|
||||
criteriaQuery = creator.createQuery(getDynamicSort(values));
|
||||
expressions = creator.getParameterExpressions();
|
||||
}
|
||||
@@ -186,11 +191,11 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
|
||||
return getEntityManager().createQuery(criteriaQuery);
|
||||
}
|
||||
|
||||
protected JpaQueryCreator createCreator(ParametersParameterAccessor accessor) {
|
||||
protected JpaQueryCreator createCreator(ParametersParameterAccessor accessor,
|
||||
PersistenceProvider persistenceProvider) {
|
||||
|
||||
EntityManager entityManager = getEntityManager();
|
||||
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||
PersistenceProvider persistenceProvider = PersistenceProvider.fromEntityManager(entityManager);
|
||||
|
||||
ParameterMetadataProvider provider = accessor == null
|
||||
? new ParameterMetadataProvider(builder, parameters, persistenceProvider)
|
||||
@@ -232,20 +237,20 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
|
||||
*/
|
||||
private class CountQueryPreparer extends QueryPreparer {
|
||||
|
||||
public CountQueryPreparer(boolean recreateQueries) {
|
||||
super(recreateQueries);
|
||||
public CountQueryPreparer(PersistenceProvider persistenceProvider, boolean recreateQueries) {
|
||||
super(persistenceProvider, recreateQueries);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jpa.repository.query.PartTreeJpaQuery.QueryPreparer#createCreator(org.springframework.data.repository.query.ParametersParameterAccessor)
|
||||
* @see org.springframework.data.jpa.repository.query.PartTreeJpaQuery.QueryPreparer#createCreator(org.springframework.data.repository.query.ParametersParameterAccessor, org.springframework.data.jpa.provider.PersistenceProvider)
|
||||
*/
|
||||
@Override
|
||||
protected JpaQueryCreator createCreator(ParametersParameterAccessor accessor) {
|
||||
protected JpaQueryCreator createCreator(ParametersParameterAccessor accessor,
|
||||
PersistenceProvider persistenceProvider) {
|
||||
|
||||
EntityManager entityManager = getEntityManager();
|
||||
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||
PersistenceProvider persistenceProvider = PersistenceProvider.fromEntityManager(entityManager);
|
||||
|
||||
ParameterMetadataProvider provider = accessor == null
|
||||
? new ParameterMetadataProvider(builder, parameters, persistenceProvider)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -70,6 +70,7 @@ public class JpaQueryLookupStrategyUnitTests {
|
||||
|
||||
when(em.getEntityManagerFactory()).thenReturn(emf);
|
||||
when(emf.createEntityManager()).thenReturn(em);
|
||||
when(em.getDelegate()).thenReturn(em);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
* Copyright 2011-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License
|
||||
import org.springframework.aop.framework.Advised;
|
||||
@@ -74,7 +74,8 @@ public class PartTreeJpaQueryIntegrationTests {
|
||||
public void test() throws Exception {
|
||||
|
||||
JpaQueryMethod queryMethod = getQueryMethod("findByFirstname", String.class, Pageable.class);
|
||||
PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager);
|
||||
PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager,
|
||||
PersistenceProvider.fromEntityManager(entityManager));
|
||||
|
||||
jpaQuery.createQuery(new Object[] { "Matthews", new PageRequest(0, 1) });
|
||||
jpaQuery.createQuery(new Object[] { "Matthews", new PageRequest(0, 1) });
|
||||
@@ -101,7 +102,8 @@ public class PartTreeJpaQueryIntegrationTests {
|
||||
public void recreatesQueryIfNullValueIsGiven() throws Exception {
|
||||
|
||||
JpaQueryMethod queryMethod = getQueryMethod("findByFirstname", String.class, Pageable.class);
|
||||
PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager);
|
||||
PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager,
|
||||
PersistenceProvider.fromEntityManager(entityManager));
|
||||
|
||||
Query query = jpaQuery.createQuery(new Object[] { "Matthews", new PageRequest(0, 1) });
|
||||
|
||||
@@ -122,8 +124,8 @@ public class PartTreeJpaQueryIntegrationTests {
|
||||
}
|
||||
Method method = UserRepository.class.getMethod(methodName, parameterTypes);
|
||||
JpaQueryMethod queryMethod = getQueryMethod(methodName, parameterTypes);
|
||||
PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager);
|
||||
|
||||
PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager,
|
||||
PersistenceProvider.fromEntityManager(entityManager));
|
||||
jpaQuery.createQuery(values);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user