Sto cercando di aggiungere il supporto multi-tenancy ai miei archivi jpa di dati Spring. Vorrei impostare dinamicamente l'ID tenant per richiesta, ma non funziona con il metodo finder personalizzato findBy * sul repository. Ho seguito questa guida: http://codecrafters.blogspot.sk/2013/03/multi-tenant-cloud-applications-with.htmlMulti tenancy con dati di primavera jpa e eclipselink
mio repository assomiglia a questo:
public interface CountryRepository extends PagingAndSortingRepository<Country, Long> {
Country findByName(String name);
Country findByIsoCountryCode(String isoCountryCode);
}
sto ottenendo l'errore sotto quando chiamo una delle finder personalizzato findBy * metodi sulla interfaccia repository:
javax.persistence.PersistenceException: Exception [EclipseLink-6174] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.QueryException
Exception Description: No value was provided for the session property [eclipselink.tenant-id]. This exception is possible when using additional criteria or tenant discriminator columns without specifying the associated contextual property. These properties must be set through Entity Manager, Entity Manager Factory or persistence unit properties. If using native EclipseLink, these properties should be set directly on the session.
Query: ReadAllQuery(referenceClass=Country sql="SELECT ID, TENANT_ID, CONTINENT, CREATED_BY, CREATED_DATETIME, CURRENCY, INDEPENDENTFROM, ISOCOUNTRYCODE, LONGNAME, MODIFIED_BY, MODIFIED_DATETIME, NAME, POPULATION, REC_VERSION FROM COUNTRY WHERE ((NAME = ?) AND (TENANT_ID = ?))")
at org.eclipse.persistence.internal.jpa.QueryImpl.getSingleResult(QueryImpl.java:547)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.getSingleResult(EJBQueryImpl.java:400)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.springframework.orm.jpa.SharedEntityManagerCreator$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:360)
at com.sun.proxy.$Proxy56.getSingleResult(Unknown Source)
at org.springframework.data.jpa.repository.query.JpaQueryExecution$SingleEntityExecution.doExecute(JpaQueryExecution.java:197)
at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:74)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:97)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:88)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:421)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:381)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.java:111)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy52.findByName(Unknown Source)
suppongo che i dati di primavera genera l'attuazione di quelli finder personalizzato findBy * metodi nella fase di inizializzazione e metterli in una cache con il gestore di entità corrente senza un ID titolare impostato su di esso e non sono in grado di impostare/modificare l'ID titolare su questo gestore entità memorizzato nella cache. Sto cercando di modificare l'ID tenant sul gestore di entità in modo dinamico per richiesta, quindi la domanda è come posso modificare/impostare l'ID tenant su quel gestore di entità cache, che viene utilizzato quando chiamo uno dei finder personalizzati findBy * Metodi.
Ecco il mio multi-tenant implementazione repository querydsl:
public class MultiTenantQueryDslJpaRepository<T, ID extends Serializable> extends QueryDslJpaRepository<T, ID> {
private final CurrentTenantResolver currentTenantResolver;
protected final EntityManager entityManager;
public MultiTenantQueryDslJpaRepository(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager, CurrentTenantResolver currentTenantResolver) {
this(entityInformation, entityManager, SimpleEntityPathResolver.INSTANCE, currentTenantResolver);
}
public MultiTenantQueryDslJpaRepository(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager, EntityPathResolver resolver, CurrentTenantResolver currentTenantResolver) {
super(entityInformation, entityManager, resolver);
this.currentTenantResolver = currentTenantResolver;
this.entityManager = entityManager;
}
protected void setCurrentTenant() {
entityManager.setProperty(PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT, currentTenantResolver.getCurrentTenantId());
}
@Override
protected JPQLQuery createQuery(final Predicate... predicate) {
setCurrentTenant();
return super.createQuery(predicate);
}
@Override
public void delete(final T entity) {
setCurrentTenant();
super.delete(entity);
}
@Override
public T findOne(final ID id) {
setCurrentTenant();
return super.findOne(id);
}
@Override
public void deleteInBatch(final Iterable<T> entities) {
setCurrentTenant();
super.deleteInBatch(entities);
}
@Override
public void deleteAllInBatch() {
setCurrentTenant();
super.deleteAllInBatch();
}
@Override
public T getOne(final ID id) {
setCurrentTenant();
return super.getOne(id);
}
@Override
public boolean exists(final ID id) {
setCurrentTenant();
return super.exists(id);
}
@Override
protected TypedQuery<T> getQuery(final Specification<T> spec, final Sort sort) {
setCurrentTenant();
return super.getQuery(spec, sort);
}
@Override
public long count() {
setCurrentTenant();
return super.count();
}
@Override
protected TypedQuery<Long> getCountQuery(final Specification<T> spec) {
setCurrentTenant();
return super.getCountQuery(spec);
}
@Override
public <S extends T> S save(final S entity) {
setCurrentTenant();
return super.save(entity);
}
}
hai trovato una soluzione per questo? –
Sì. La soluzione si basa sulla gestione specifica di eclipse-link di BindCallCustomParameter che viene aggiunto come titolare del titolare alla mappa delle proprietà EM. – Ati