Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Solutions for a simple multi tenant web application with entity framework

I'm developing a multi-tenant web app (stack: MVC 4 + Entity framework 4.3). My requirements are pretty simple: each tenant has the same UI and CodeBase.

In my database I have some tables with a TenantId field (and other tables without).

I have set up a very simple generic repository:

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;
    }

I'd like the "get" methods to filter for my tenantId. My insert, update and delete method should also constrain the appropriete TenantId.

My Entities are autogenerated POCO classes.

I have considered these solutions:

1- GenericRepository should implement a "ITenant" interface that defines TenantId. Problem is that some entities haven't got the TenantId property. Also, I don't really like to modify the T4 template I use to generate POCO objects to make them implement my interface

2- Reflection (but of course EF can't translate it to a SQL statement)

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

What would you do in my case? I'm willing to reconsider my architecture if necessary.

Thanks, Nicola

like image 887
Nicola Cassolato Avatar asked Jul 10 '12 11:07

Nicola Cassolato


1 Answers

You can do the reflection check and then manually create an expression tree that EF can understand.

For example:

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);
}
like image 79
João Angelo Avatar answered Sep 20 '22 18:09

João Angelo