I have a standard DbContext
with code like the following:
public DbSet<Interest> Interests { get; set; }
public DbSet<User> Users { get; set; }
I've recently implemented multi-tenancy by creating a TenantContext
that contains the following:
private readonly DbContext _dbContext;
private readonly Tenant _tenant;
public TenantContext(Tenant tenant)
: base("name=DefaultConnection") {
this._tenant = tenant;
this._dbContext = new DbContext();
}
public IQueryable<User> Users { get { return FilterTenant(_dbContext.Users); } }
public IQueryable<Interest> Interests { get { return FilterTenant(_dbContext.Interests); } }
private IQueryable<T> FilterTenant<T>(IQueryable<T> values) where T : class, ITenantData
{
return values.Where(x => x.TenantId == _tenant.TenantId);
}
So far, this has been working great. Whenever any of my services creates a new TenantContext, all queries directly off of that context are filtered through this FilterTenant
method that guarantees I'm only returning tenant-relevant entities.
The problem that I'm encountering is my usage of navigation properties that do not take this into account:
using (var db = CreateContext()) // new TenantContext
{
return db.Users.
Include(u => u.Interests).FirstOrDefault(s => s.UserId == userId);
}
This query pulls up the tenant-specific Users
, but then the Include()
statement pulls in Interests
for that user only - but across all tenants. So if a user has Interests across multiple Tenants, I get all of the user's Interests with the above query.
My User model has the following:
public int UserId { get; set; }
public int TenantId { get; set; }
public virtual ICollection<Interest> Interests { get; set; }
Is there any way that I can somehow modify these navigation properties to perform tenant-specific queries? Or should I go and tear out all navigation properties in favor of handwritten code?
The second option scares me because a lot of queries have nested Includes. Any input here would be fantastic.
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…