我有一个标准DbContext
,代码如下:
public DbSet<Interest> Interests { get; set; }
public DbSet<User> Users { get; set; }
我最近通过创建一个TenantContext
包含以下内容来实现多租户:
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);
}
到目前为止,这一直很好。每当我的任何服务创建新的 TenantContext 时,直接从该上下文中获取的所有查询都会通过此FilterTenant
方法过滤,以确保我只返回与租户相关的实体。
我遇到的问题是我对导航属性的使用没有考虑到这一点:
using (var db = CreateContext()) // new TenantContext
{
return db.Users.
Include(u => u.Interests).FirstOrDefault(s => s.UserId == userId);
}
此查询提取特定于租户的Users
,但随后该Include()
语句Interests
仅针对该用户提取 - 但跨所有租户。因此,如果用户对多个租户有兴趣,我会通过上述查询获得所有用户的兴趣。
我的用户模型具有以下内容:
public int UserId { get; set; }
public int TenantId { get; set; }
public virtual ICollection<Interest> Interests { get; set; }
有什么方法可以修改这些导航属性以执行特定于租户的查询?还是我应该去掉所有导航属性以支持手写代码?
第二个选项让我害怕,因为很多查询都嵌套了 Includes。这里的任何输入都会很棒。