2014-10-27 12 views
5

Ich versuche, meine Frühjahr Daten jpa Repositories Multi-Mandanten-Unterstützung hinzufügen. Ich möchte dynamisch die Mandanten-ID pro Anfrage festlegen, aber es funktioniert nicht für den benutzerdefinierten Finder findBy * Methoden auf Repository. Ich habe diese Anleitung gefolgt: http://codecrafters.blogspot.sk/2013/03/multi-tenant-cloud-applications-with.htmlMulti-Tenancy mit Frühjahr Daten jpa und Eclipselink

Mein Repository wie folgt aussieht:

public interface CountryRepository extends PagingAndSortingRepository<Country, Long> { 

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

} 

Ich erhalte den Fehler unten, wenn ich eine der benutzerdefinierten finder nennen findBy * Methoden auf die Repository-Schnittstelle:

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) 

ich gehe davon aus, dass Daten, die die Feder Durchführung dieser benutzerdefinierten finder erzeugt findBy * Methoden in der Initialisierungsphase und legen Sie sie in einen Cache mit dem aktuellen Entity Manager, ohne dass eine Mandanten-ID festgelegt wurde. Ich kann die Mandanten-ID für diesen zwischengespeicherten Entity Manager nicht festlegen/ändern. Ich versuche, die Tenant-ID im Entity Manager dynamisch pro Anfrage zu ändern, also lautet die Frage, wie kann ich die Tenant-ID in diesem zwischengespeicherten Entity-Manager ändern/setzen, der verwendet wird, wenn ich einen benutzerdefinierten Finder anrufe findBy * Methoden.

Hier ist meine Multi-Tenant-querydsl Repository Implementierung:

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

haben Sie Lösung für dieses? –

+0

Ja. Die Lösung basiert auf der Eclipse-Link-spezifischen Behandlung von BindCallCustomParameter, die als Tenant Holder der EM-Eigenschaftszuordnung hinzugefügt wird. – Ati

Antwort

2

Die Lösung auf Eclipse-Link spezifischen Umgang mit BindCallCustomParameter basiert, die als Mieter Halter EM Immobilien Karte hinzugefügt wird.

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

Das ist alles, was Sie brauchen, um mit Eclipselink und Spring Data arbeiten zu können? Sie brauchen keine benutzerdefinierten Repositories mehr? –

+0

Können Sie die Tentant-ID mit benutzerdefinierten Repositorys pro Anfrage festlegen? – Ati

+1

Können Sie uns bitte mitteilen, welche EM-Eigenschaft Sie verwendet haben? – Ljudevit