I have a similar problem in my database. 90% of my entities are "organisation dependent". My approach uses a generic base repository with methods like this:
public virtual T Find(int id)
{
T e = Context.Set<T>().Find(id);
var od = e as OrganisationDependent;
if (od != null && od.OrganisationID != CurrentOrganisationID)
return null;
if (e == null)
return null;
return e;
}
The "All" method was a particular issue. Solved by How to conditionally filter IQueryable
private static readonly PropertyInfo _OrganisationIDProperty = ReflectionAPI.GetProperty<OrganisationDependent, int>(o => o.OrganisationID);
private static Expression<Func<TOrg, bool>> FilterByOrganization<TOrg>(int organizationId)
{
//The FilterByOrganisation method uses the LINQ Expressions API to generate an expression that will filter on organisation id
//This avoids having to cast the set using .AsEnumerable().Cast<OrganisationDependent>().Where(x => x.OrganisationID == CurrentOrganisationID).AsQueryable().Cast<T>();
//https://stackoverflow.com/questions/20052827/how-to-conditionally-filter-iqueryable-by-type-using-generic-repository-pattern
var item = Expression.Parameter(typeof(TOrg), "item");
var propertyValue = Expression.Property(item, _OrganisationIDProperty);
var body = Expression.Equal(propertyValue, Expression.Constant(organizationId));
return Expression.Lambda<Func<TOrg, bool>>(body, item);
}
public virtual IQueryable<T> All
{
get
{
if (typeof(T).IsSubclassOf(typeof(OrganisationDependent)))
return Context.Set<T>().Where(FilterByOrganization<T>(CurrentOrganisationID));
return Context.Set<T>();
}
}
This closes off most of the places that a user could access someone else's data. But it doesn't filter navigational properties. So I have to add code to all navigation properties on non-organisation dependent entities to do that.
I don't want to separate my data into different database, but one day I will find out if it's feasible to create views filtered by organisation in different schemas - with the same name and structure as my tables, then switch schema according to user.....oh and I want to automatically create them for each new organisation and autmatically migrate them using code-first too....
And you could vote to Allow filtering for Include extension method here