2014-10-27 25 views
5

Próbuję dodać obsługę wielu dzierżawców do moich repozytoriów danych Spring jpa. Chciałbym ustawić dynamicznie identyfikator dzierżawcy na żądanie, ale nie działa ono dla niestandardowych metod wyszukiwania w repozytorium. ja po tej instrukcji: http://codecrafters.blogspot.sk/2013/03/multi-tenant-cloud-applications-with.htmlMulti-dzierżawa z danymi sprężynowymi jpa i eclipselink

Moje repozytorium wygląda tak:

public interface CountryRepository extends PagingAndSortingRepository<Country, Long> { 

    Country findByName(String name); 
    Country findByIsoCountryCode(String isoCountryCode); 

} 

Otrzymuję błąd poniżej kiedy wywołać dowolną niestandardowej wyszukiwarki findBy * metody na repozytorium interfejs:

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) 

Zakładam, że dane sprężyna generuje wdrożenia tych niestandardowej wyszukiwarki findBy * metody na etapie inicjalizacji i umieść je w pamięci podręcznej z bieżącym menedżerem encji bez ustawionego na nim identyfikatora dzierżawy i nie jestem w stanie ustawić/zmienić identyfikatora dzierżawcy w tym buforowanym menedżerze encji. Próbuję zmienić identyfikator dzierżawcy w menedżerze encji dynamicznie według żądania, więc pytanie brzmi: jak zmienić/ustawić identyfikator dzierżawcy w tym menedżerze encji, który jest używany, gdy wywołuję dowolną z niestandardowych wyszukiwaczy findBy * metody.

Oto moja multitenant realizacja repozytorium 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); 
} 
} 
+0

znaleźliście rozwiązanie tego problemu? –

+0

Tak. Rozwiązanie opiera się na specyficznej obsłudze BindCallCustomParameter przy użyciu Eclipse-link, która jest dodawana jako właściciel dzierżawcy do mapy właściwości EM. – Ati

Odpowiedz

2

Rozwiązanie jest oparte na Eclipse-link specyficznej obsługi BindCallCustomParameter która jest dodawana jako posiadacz najemcy EM własności mapie.

public class TenantHolder extends BindCallCustomParameter { 

private final TenantResolver tenantResolver; 

private String defaultTenant; 

public TenantHolder(String defaultTenant, TenantResolver tenantResolver) { 
    this.defaultTenant = defaultTenant; 
    this.tenantResolver = tenantResolver; 
} 

public String getDefaultTenant() { 
    return defaultTenant; 
} 

@Override 
public void set(DatabasePlatform platform, PreparedStatement statement, int index, AbstractSession session) throws SQLException { 
    String resolvedTenant = resolveTenant(); 
    platform.setParameterValueInDatabaseCall(resolvedTenant, statement, index, session); 
} 

private String resolveTenant() { 
    return tenantResolver.resolveTenant(defaultTenant); 
} 

}

+0

A więc to wszystko, czego potrzebujesz, aby pracować z urządzeniami Eclipselink i Spring Data? Nie ma już potrzeby tworzenia niestandardowych repozytoriów? –

+0

Czy można ustawić identyfikator obiektu z niestandardowymi repozytoriami dla każdego żądania? – Ati

+1

Czy możesz podzielić się tym, z jakiej własności EM korzystałeś? – Ljudevit

Powiązane problemy