代码之家  ›  专栏  ›  技术社区  ›  exlnt

如何实现实体框架核心数据过滤器?

  •  1
  • exlnt  · 技术社区  · 6 年前

    在我的ASP.NET Zero应用程序中,我想通过 CompanyId 价值观。 here 以及在这个支持论坛上提供的信息 thread

    在我的EF核心项目中,我做了以下更改。

    public override void PreInitialize()
    {
        if (!SkipDbContextRegistration)
        {
            // ...
    
            Configuration.UnitOfWork.RegisterFilter("CompanyFilter", false);
        }
    }
    

    IMustHaveTenant 数据筛选并将以下更改应用到my DB context类中:

    protected int? CurrentCompanyId = null;
    protected bool IsCompanyFilterEnabled => CurrentCompanyId != null && CurrentUnitOfWorkProvider?.Current?.IsFilterEnabled("CompanyFilter") == true;    
    
    protected override bool ShouldFilterEntity<TEntity>(IMutableEntityType entityType)
    {
        if (typeof(IHasCompany).IsAssignableFrom(typeof(TEntity)))
        {
            return true;
        }
        return false;
    }
    
    protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>()
    {
        Expression<Func<TEntity, bool>> expression = null;
    
        if (typeof(IHasCompany).IsAssignableFrom(typeof(TEntity)))
        {
            Expression<Func<TEntity, bool>> companyFilter = e => ((IHasCompany)e).CompanyId == CurrentCompanyId || (((IHasCompany)e).CompanyId == CurrentCompanyId) == IsCompanyFilterEnabled;
            expression = expression == null ? companyFilter : CombineExpressions(expression, companyFilter);
        }
        return base.CreateFilterExpression<TEntity>();
    }
    

    然后,在我希望应用过滤器的app service方法中,我添加了下面的代码。

    public async Task<PagedResultDto<EmployeeListDto>> GetEmployees(GetEmployeeInput input)
    {
        using (CurrentUnitOfWork.EnableFilter("CompanyFilter"))
        {
            using (CurrentUnitOfWork.SetFilterParameter("CompanyFilter", "CompanyId", GetCurrentUserCompany()))
            {
                // ...
            }
        }
    }
    

    在DB context类中,如果我 硬代码 下一行的值,过滤器 .

    protected int? CurrentCompanyId = 123;
    

    我将是诚实的,我不完全理解的代码,正在使用中的 CreateFilterExpression 我必须租客 过滤器。

    公司ID . 这允许将每个用户分配到一个公司,因此应用程序应该按公司限制该用户的所有数据。

    在我的应用程序服务基类中,我有一个名为 GetCurrentUserCompany

    问题:

    • 我需要在DB context类中设置这个company值吗?
    • 如果是,那么如何调用应用程序服务或存储库方法来获取 在这个DB上下文类中?

    更新:

    App service showing filter (line 71) has been set.

    Debug cmd window showing company filter is set.

    当第77行执行并对存储库执行GetAll调用时,它仍然向用户显示所有公司。

    10月6日更新: ,但仅当用户分配了公司Id时。当用户没有分配公司时,将抛出下图所示的错误。 DB context error

    1 回复  |  直到 6 年前
        1
  •  1
  •   aaron    6 年前
    • 我需要在Db context类中设置这个company值吗?

    DbContext 班级:

    // using Abp.Collections.Extensions;
    
    // protected int? CurrentCompanyId = null;
    protected int? CurrentCompanyId => GetCurrentCompanyIdOrNull();
    
    protected virtual int? GetCurrentCompanyIdOrNull()
    {
        if (CurrentUnitOfWorkProvider != null &&
            CurrentUnitOfWorkProvider.Current != null)
        {
            return CurrentUnitOfWorkProvider.Current
                .Filters.FirstOrDefault(f => f.FilterName == "CompanyFilter")?
                .FilterParameters.GetOrDefault("CompanyId") as int?;
        }
    
        return null;
    }
    

    返回 expression 在你的 CreateFilterExpression 方法:

    protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>()
    {
        // Expression<Func<TEntity, bool>> expression = null;
        var expression = base.CreateFilterExpression<TEntity>();
    
        if (typeof(IHasCompany).IsAssignableFrom(typeof(TEntity)))
        {
            Expression<Func<TEntity, bool>> companyFilter = e => ((IHasCompany)e).CompanyId == CurrentCompanyId || (((IHasCompany)e).CompanyId == CurrentCompanyId) == IsCompanyFilterEnabled;
            expression = expression == null ? companyFilter : CombineExpressions(expression, companyFilter);
        }
    
        // return base.CreateFilterExpression<TEntity>();
        return expression;
    }
    

    Implement OrganizationUnit filter in ASP.NET Core