如何实现 Entity Framework 核心数据过滤器?

How to implement Entity Framework Core data filters?

在我的 ASP.NET 零应用程序中,我想按 CompanyId 值设置数据过滤器。 所以我阅读了文档 here and the information provided on this support forum thread.

在我的 EF Core 项目中,我进行了以下更改。

public override void PreInitialize()
{
    if (!SkipDbContextRegistration)
    {
        // ...

        Configuration.UnitOfWork.RegisterFilter("CompanyFilter", false);
    }
}

然后我遵循用于 IMustHaveTenant 数据过滤器的模式并将以下更改应用到我的数据库上下文 class:

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

然后,在我希望应用过滤器的应用服务方法中,我添加了以下代码。

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

在数据库上下文 class 中,如果我 硬编码 下面一行的 CompanyId 值,过滤器 很好.

protected int? CurrentCompanyId = 123;

老实说,我不完全理解数据库上下文 class 中 CreateFilterExpression 方法中使用的代码。我直接从 IMustHaveTenant 过滤器的 ABP GitHub 回购代码中借用了这个。

我修改了 ABP 用户 "My Settings" 模式以包含 CompanyId。这允许将每个用户分配给一家公司,因此应用程序应按公司限制该用户的所有数据。

在我的应用程序服务库 class 中,我有一个名为 GetCurrentUserCompany 的方法。此方法获取当前用户的默认公司。这是应在公司的数据过滤器上使用的值。

问题:

更新: 我添加了 Aaron 建议的代码,但它仍然无法正常工作。我正在使用分配了公司 1 的用户 ID 进行测试。然而,当数据加载时,它仍然显示公司 1 和 2。

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

10 月 6 日更新: 新代码 有效 ,但仅当用户分配了公司 ID 时。当用户没有分配公司时,会抛出下图所示的错误。

  • Do I need to set this company value in the Db context class?
  • If yes, then how do I call an app service or repository method to get the company Id in this DB context class?

没有。在您的 DbContext class:

中实施 getter
// 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;
}

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

类似问题: