1

Based on the ASP.net MVC tutorial's GenericRepository pattern (Implementing the Repository and Unit of Work Patterns in an ASP.NET MVC Application), what speaks against implementing multi tenancy as follows:

public class GenericMultiTenantRepository<TEntity> where TEntity : MultitenantEntity
{
    internal SchoolContext context;
    internal DbSet<TEntity> dbSet;
    ...
public virtual IEnumerable<TEntity> Get(
        Expression<Func<TEntity, bool>> filter = null,
        Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
        string includeProperties = "")
    {
        IQueryable<TEntity> query = dbSet;

        if (filter != null)
        {
            query = query.Where(filter);
        }

        query = query.Where(entity => entity.TenantId == <TenantId>); /* Like this? */

        foreach (var includeProperty in includeProperties.Split
            (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
        {
            query = query.Include(includeProperty);
        }

        if (orderBy != null)
        {
            return orderBy(query).ToList();
        }
        else
        {
            return query.ToList();
        }
    }

and MultitenantEntity just being the following:

public class MultitenantEntity {
    public int TenantId {get;set;}
}

All entities now derive from MultitenantEntity and you can still program the entire app as if it was intended for just one tenant?

Am I overseeing something? Or is there a more widely accepted practice to achieve what I'm trying to do?

The same principles should be added to the insert method as well, but I omitted those changes for brevity.

senic
  • 147
  • 6

1 Answers1

2

Am I overseeing something?

No, that's basically it, if you want an entity to only ever be owned by one 'tenant'. I'm currently R&D'ing an even more generic framework that allows permissions to be assigned to each entity and repository, implementing CRUD and other permissions for single users and groups of users. I couldn't find any existing paid or free library to do this.

Keep in mind that when inserting or updating, you'll have to check for overposting / mass assignment of related entities, where a malicious user can change the key fields (like ID) being posted.

If you don't, someone can call Update(TEntity entity) where entity is writable by the currently logged on user, but where entity.RelatedEntity actually belongs to someone else.

Of course in your case, you'd want to abstract merely the multi-tenancy-related code, so your Get() becomes:

public override virtual IEnumerable<TEntity> Get(
    Expression<Func<TEntity, bool>> filter = null,
    Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
    string includeProperties = "")
{
    return base.Get(filter, orderBy, includeProperties)
               .Where(entity => entity.TenantId == _tenantID);
}
CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • Hi CodeCaster - I'm trying to implement something similar but I'm running into difficulties with virtual properties. If you get a minute, would you mind taking a peek at this? http://stackoverflow.com/questions/19826316/virtual-navigation-properties-and-multi-tenancy – RobVious Nov 07 '13 at 16:24