2012-07-10 13 views
5

Estoy desarrollando una aplicación web multi-tenant (pila: MVC 4 + Entity framework 4.3). Mis requisitos son bastante simples: cada inquilino tiene la misma interfaz de usuario y Codebase.Soluciones para una aplicación web multi inquilino simple con entidad marco

En mi base de datos tengo algunas tablas con un campo TenantId (y otras tablas sin).

He creado un muy simple repositorio genérico:

public class GenericRepository<TEntity> where TEntity : class 
{ 
    internal Database.CRMEntities context; 
    internal DbSet<TEntity> dbSet; 
    internal int tenantId; 

    public GenericRepository(Database.CRMEntities context) 
    { 
     this.context = context; 
     this.dbSet = context.Set<TEntity>(); 
     this.tenantId = 1; 
    } 

me gustaría los métodos "get" para filtrar por mi tenantId. Mi método de inserción, actualización y eliminación también debe restringir el TenantId apropiado.

Mis entidades son clases de POCO autogeneradas.

me han considerado estas soluciones:

1- GenericRepository debe implementar una interfaz "ITenant" que define TenantId. El problema es que algunas entidades no tienen la propiedad TenantId. Además, realmente no me gusta para modificar la plantilla T4 que utilizo para generar objetos POCO para hacerlos implementan la interfaz de mi

2- Reflexión (pero por supuesto EF no puede traducirlo a una instrucción SQL)

if (typeof(TEntity).GetProperty("TenantId") != null) 
      query = query.Where(x => (int) (x.GetType().GetProperty("TenantId").GetValue(x, null)) == tenantId); 

¿Qué harías en mi caso? Estoy dispuesto a reconsiderar mi arquitectura si es necesario.

Gracias, Nicola

Respuesta

5

Se puede hacer el check reflexión y luego crear manualmente un árbol de expresión que EF puede entender.

Por ejemplo:

int tenantId = 5; 

var tenantIdInfo = typeof(TEntity).GetProperty("TenantId"); 

if (tenantIdInfo != null) 
{ 
    var entity = Expression.Parameter(typeof(TEntity), "it"); 

    var predicate = (Expression<Func<TEntity, bool>>)Expression.Lambda(
     Expression.Equal(
      Expression.MakeMemberAccess(entity, tenantIdInfo), 
      Expression.Constant(tenantId, typeof(int))), 
     entity); 

    query = query.Where(predicate); 
} 
+0

Gracias por la respuesta. Una expresión debería funcionar ... y es una pieza de código bastante simple para manejar un problema complejo. Me preguntaba ... ¿el reflejo es "lento" o puedo usarlo sin ningún problema? –

+0

La reflexión tiene un impacto considerable en el rendimiento, pero deberá medirla para su escenario específico para ver si es aceptable o no. –

+0

Realicé algunas pruebas: una consulta de selección repetida 1000 veces y devolver solo una fila es aproximadamente un 5% más lenta. Esa no es una prueba completa, pero por ahora es suficiente. Voy a marcar mi pregunta como respondida si a nadie se le ocurre una idea mejor en un par de días. Gracias! –

Cuestiones relacionadas