我试图实现一个多租户应用程序,我通过租户对象查询数据库,而不是直接关闭的情况下。之前,我有这样的:
I'm attempting to implement a multi-tenant application where I query the db via the tenant object, instead of directly off the context. Before I had this:
public User GetUserByEmail(string email) { using (var db = CreateContext()) { return db.Users.FirstOrDefault(u => u.Email.Equals(email, StringComparison.OrdinalIgnoreCase)); } }现在我有这样的:
public User GetUserByEmail(string email) { using (var db = CreateContext()) { return _tenant.Users.FirstOrDefault(u => u.Email.Equals(email, StringComparison.OrdinalIgnoreCase)); } }如果租户如下:
public class Tenant { public Tenant() { } [Key] [Required] public int TenantId { get; set; } public virtual DbSet<User> Users { get; set; } // etc }我在哪里User模型有以下几点:
Where my User model has the following:
public virtual List<Tenant> Tenants { get; set; }在我的语境配置,我有以下几点:
And in my Context configuration, I have the following:
modelBuilder.Entity<Tenant>() .HasMany(e => e.Users) .WithMany() .Map(m => { m.ToTable("UserTenantJoin"); m.MapLeftKey("TenantId"); m.MapRightKey("UserId"); });但我遇到的事实,DbSet是与上面的模型构建器不兼容的问题 - 它扼流圈的hasMany说,使用DbSet不能从使用中推断出来。
But I'm running into a problem with the fact that DbSet is incompatible with the ModelBuilder above - it chokes on HasMany saying that the use of DbSet cannot be inferred from usage.
我打了使用ICollection的代替,但在我的业务层 _tenant.Users.Include所有呼叫(东西)或查找( ),和其他的数据库查询断裂。
I played with using ICollection instead, but then in my service layer all calls to _tenant.Users.Include(stuff), or Find(), and other db queries break.
这打破如果我用一个ICollection的服务方法的例子:
Example of a service method that breaks if I use ICollection:
public User GetUserWithInterestsAndAptitudes(string username) { using (var db = CreateContext()) { return _tenant.Users. // can't use .Include on ICollection Include(u => u.Relationships). Include(u => u.Interests). Include(u => u.Interests.Select(s => s.Subject)). Include(u => u.Interests.Select(s => s.Aptitude)). FirstOrDefault(s => s.Username.Equals(username, StringComparison.OrdinalIgnoreCase)); } }我希望能有一个解决方案,让我继续导航性能可查询,而无需重新架构我的服务层。
I'm hoping there's a solution that will allow me to keep the navigation properties queryable without re-architecting my service layer.
一种选择是,我通过 db.Users 恢复一切回到使用上下文,然后添加其他条件,每一个查询。凡(U =&GT; u.TenantId == _tenant.TenantId)。 - 但我想避免这种
One option is that I revert everything back to using the context via db.Users, and then add another condition to every single query .Where(u => u.TenantId == _tenant.TenantId) - but I'm trying to avoid this.
在这里的任何帮助将非常AP preciated。
Any help here would be much appreciated.
推荐答案我也有类似你正试图避免什么解决方案。
I have a solution similar to what you are trying to avoid.
我有一个只能通过TenantContext访问一个真正的DbContext。
I have a real DbContext that is only accessed via a TenantContext.
public class RealContext { public DbSet<User> Users { get; set; } [...] } public class TenantContext { private RealContext realContext; private int tenantId; public TenantContext(int tenantId) { realContext = new RealContext(); this.tenantId= tenantId; } public IQueryable<User> Users { get { FilterTenant(realContext.Users); } } private IQueryable<T> FilterTenant<T>(IQueryable<T> values) where T : class, ITenantData { return values.Where(x => x.TenantId == tenantId); } public int SaveChanges() { ApplyTenantIds(); return realContext.SaveChanges(); } }使用这个方法我敢肯定,没有一个是可以查询没有得到正确的住户发送。对于从上下文中添加和删除项目我使用这两个泛型方法。
Using this method I'm sure that there is no was a query can be sent without getting the correct tenants. For adding and removing items from the context I' using those two generic methods.
public void Remove<T>(params T[] items) where T : class, ITenantData { var set = realContext.Set<T>(); foreach(var item in items) set.Remove(item); } public void Add<T>(params T[] items) where T : class, ITenantData { var set = realContext.Set<T>(); foreach (var item in items) set.Add(item); }更多推荐
DbSet,模型构建器和EF导航属性
发布评论