简体   繁体   English

多租户实体过滤

[英]Multi-tenant entity filtration

I'm working on multi-tenant application where different companies are differs by CompanyID column. 我正在多租户应用程序中,根据CompanyID列,不同的公司有所不同。 There are also common core tables in database like Settings which are the same for all the companies. 数据库中还有一些通用的核心表,例如Settings ,对于所有公司都是相同的。 I have two base persistent classes: PersistentObject and CompanyPersistentObject . 我有两个基本的持久化类: PersistentObjectCompanyPersistentObject The last one inherits from the first and adds CompanyId property. 最后一个继承自第一个,并添加CompanyId属性。 I'm going to insert company ID criteria directly in repository like this: 我将直接在存储库中插入公司ID标准,如下所示:

public class EntityFrameworkRepository<T> : Repository<T>
    where T : PersistentObject
{
    private readonly DbSet<T> set;
    private readonly IApplicationContext applicationContext;
    private readonly IQueryable<T> queryable;

    public EntityFrameworkRepository(DbSet<T> set,
                                     IApplicationContext applicationContext)
    {
        this.set = set;
        this.applicationContext = applicationContext;

        if (typeof (CompanyPersistentObject).IsAssignableFrom(typeof(T)))
        {
            // TODO: Apply CompanyPersistentObject filter
            // using applicationContext.CompanyID
        }
    }
}

Is this good approach or you can suggest the better solution? 这是一个好方法还是您可以提出更好的解决方案?
If so how to inject the criteria for CompanyPersistentObject in DbSet<T> where T is PersistentObject and have no CompanyId property? 如果是的话,如何在DbSet<T>中注入CompanyPersistentObject的条件,其中TPersistentObject并且没有CompanyId属性?

I do almost exactly what you are proposing in my application. 我几乎完全按照您在我的申请中的建议去做。 The method I found trickiest to implement was the "All" wrapper. 我发现最难以实现的方法是“全部”包装器。 I wanted to return an IQueryable but linq to entities does not support casting to entities. 我想返回一个IQueryable但是对实体的linq不支持强制转换为实体。 The answer to that problem was provided here: 这个问题的答案在这里提供:

How to conditionally filter IQueryable by type using generic repository pattern 如何使用通用存储库模式按类型有条件地过滤IQueryable

I did actually start out using the technique that Martin Eden suggests, but I re-factored it into a single base repository as you are proposing, and it is now much simpler and safer. 实际上,我确实是使用Martin Eden建议的技术开始的,但是我按照您的建议将其重构为单个基本存储库,现在它变得更加简单和安全。

This is what my "Find" method looks like: 这是我的“查找”方法的样子:

    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;
    }

I would suggest that you instead extend your EntityFrameworkRepository class with a CompanyRepository class that has this behaviour. 我建议您改用具有此行为的CompanyRepository类扩展EntityFrameworkRepository类。 Then you could constrain the type parameter of CompanyRepository to only be classes that extend CompanyPersistentObject (or better, an interface). 然后,您可以将CompanyRepository的类型参数约束为仅扩展CompanyPersistentObject(或更好的是接口)的类。

For example: 例如:

public class EntityFrameworkRepository<T> : Repository<T>
    where T : PersistentObject
{
    private readonly DbSet<T> set;
    private readonly IApplicationContext applicationContext;
    private readonly IQueryable<T> queryable;

    public EntityFrameworkRepository(DbSet<T> set,
                                 IApplicationContext applicationContext)
    {
        this.set = set;
        this.applicationContext = applicationContext;
    }
}


public class CompanyRepository<T> : Repository<T>
    where T : PersistentObject, ICompany
{
    public CompanyRepository(DbSet<T> set,
                                 IApplicationContext applicationContext)
    {
        this.set = setFilteredById(set, applicationContext.CompanyId);    
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM