文章翻译:ABP如何在EF core中添加数据过滤器
原文地址:https://aspnetboilerplate.com/Pages/Documents/Articles%5CHow-To%5Cadd-custom-data-filter-ef-core
在本文中,我将解释如何在EF core中添加自定义数据过滤器。
我们将为OrganizationUnit 创建一个过滤器,并从IMayHaveOrganizationUnit
接口继承的实体,根据登录用户的组织单元自动过滤。
我们将使用asp.net core和asp.net查询模板。您可以在https://aspnetboilerplate.com/templates上创建一个项目,并应用以下步骤来查看自定义组织单元筛选器的运行情况。
创建和更新实体
创建实体
创建名为Document的实体继承自IMayHaveOrganizationUnit接口(IMayHaveOrganizationUnit接口在abp框架中定义)。
public class Document : Entity, IMayHaveOrganizationUnit
{
public string Title { get; set; } public string Content { get; set; } public long? OrganizationUnitId { get; set; }
}
在你的DbContext中添加Document实体
更新User类
向user.cs添加OrganizationUnitId。我们将使用用户的OrganizationUnitId 字段来过滤Document实体。
public class User : AbpUser<User>
{
public const string DefaultPassword = "123qwe"; public static string CreateRandomPassword()
{
return Guid.NewGuid().ToString("N").Truncate(16);
} public int? OrganizationUnitId { get; set; } public static User CreateTenantAdminUser(int tenantId, string emailAddress)
{
var user = new User
{
TenantId = tenantId,
UserName = AdminUserName,
Name = AdminUserName,
Surname = AdminUserName,
EmailAddress = emailAddress
}; user.SetNormalizedNames(); return user;
}
}
添加迁移
使用add migration命令添加迁移并运行update database以将更改应用于数据库。
创建Claim
我们需要在Claim中存储登录用户的OrganizationUnitId ,这样就可以得到它,以便在DbContext中过滤IMayHaveOrganizationUnit 实体。为此,重写UserClaimsPrincipalFactory类的CreateAsync方法,并将登录用户的 OrganizationUnitId 添加到如下声明中。
public class UserClaimsPrincipalFactory : AbpUserClaimsPrincipalFactory<User, Role>
{
public UserClaimsPrincipalFactory(
UserManager userManager,
RoleManager roleManager,
IOptions<IdentityOptions> optionsAccessor)
: base(
userManager,
roleManager,
optionsAccessor)
{
} public override async Task<ClaimsPrincipal> CreateAsync(User user)
{
var claim = await base.CreateAsync(user);
claim.Identities.First().AddClaim(new Claim("Application_OrganizationUnitId", user.OrganizationUnitId.HasValue ? user.OrganizationUnitId.Value.ToString() : "")); return claim;
}
}
注册过滤器
在筛选DbContext中的实体之前,我们将注册过滤器,以便在代码中的某些情况下禁用它。
在YourProjectNameEntityFrameworkModule 的PreInitialize 方法中注册筛选器,以从当前工作单元管理器获取它。
public override void PreInitialize()
{
... //register filter with default value
Configuration.UnitOfWork.RegisterFilter("MayHaveOrganizationUnit", true);
}
配置DbContext
我们需要使用OrganizationUnitId 的值来过滤DbContext中的IMayHaveOrganizationUnit 实体。
为此,首先在DbContext中添加如下字段:
protected virtual int? CurrentOUId => GetCurrentUsersOuIdOrNull();
在DbContext中定义如下GetCurrentUsersOuIdOrNull方法,并使用propert注入将IPrincipalAccessor 注入到DbContext中;
public class CustomFilterSampleDbContext : AbpZeroDbContext<Tenant, Role, User, CustomFilterSampleDbContext>
{
public DbSet<Document> Documents { get; set; } public IPrincipalAccessor PrincipalAccessor { get; set; } protected virtual int? CurrentOUId => GetCurrentUsersOuIdOrNull(); public CustomFilterSampleDbContext(DbContextOptions<CustomFilterSampleDbContext> options)
: base(options)
{ } protected virtual int? GetCurrentUsersOuIdOrNull()
{
var userOuClaim = PrincipalAccessor.Principal?.Claims.FirstOrDefault(c => c.Type == "Application_OrganizationUnitId");
if (string.IsNullOrEmpty(userOuClaim?.Value))
{
return null;
} return Convert.ToInt32(userOuClaim.Value);
}
}
之后,让我们向DbContext添加一个属性,以获取MayHaveOrganizationUnit 过滤器是否已启用。
protected virtual bool IsOUFilterEnabled => CurrentUnitOfWorkProvider?.Current?.IsFilterEnabled("MayHaveOrganizationUnit") == true;
AbpDbContext 定义了两个与数据筛选器相关的方法。一个是ShouldFilterEntity ,另一个是CreateFilterExpression。ShouldFilterEntity方法决定是否过滤实体。CreateFilterExpression方法为要筛选的实体创建筛选表达式。
为了过滤从IMayHaveOrganizationUnit继承的实体,我们需要重写这两个方法。
首先,重写如下所示的ShouldFilterEntity 方法;
protected override bool ShouldFilterEntity<TEntity>(IMutableEntityType entityType)
{
if (typeof(IMayHaveOrganizationUnit).IsAssignableFrom(typeof(TEntity)))
{
return true;
} return base.ShouldFilterEntity<TEntity>(entityType);
}
然后,重写CreateFilterExpression方法,如下所示;
protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>()
{
var expression = base.CreateFilterExpression<TEntity>(); if (typeof(IMayHaveOrganizationUnit).IsAssignableFrom(typeof(TEntity)))
{
Expression<Func<TEntity, bool>> mayHaveOUFilter = e => ((IMayHaveOrganizationUnit)e).OrganizationUnitId == CurrentOUId || (((IMayHaveOrganizationUnit)e).OrganizationUnitId == CurrentOUId) == IsOUFilterEnabled;
expression = expression == null ? mayHaveOUFilter : CombineExpressions(expression, mayHaveOUFilter);
} return expression;
}
以下是DbContext的最终版本:
public class CustomFilterSampleDbContext : AbpZeroDbContext<Tenant, Role, User, CustomFilterSampleDbContext>
{
public DbSet<Document> Documents { get; set; } public IPrincipalAccessor PrincipalAccessor { get; set; } protected virtual int? CurrentOUId => GetCurrentUsersOuIdOrNull(); protected virtual bool IsOUFilterEnabled => CurrentUnitOfWorkProvider?.Current?.IsFilterEnabled("MayHaveOrganizationUnit") == true; public CustomFilterSampleDbContext(DbContextOptions<CustomFilterSampleDbContext> options)
: base(options)
{ } protected override bool ShouldFilterEntity<TEntity>(IMutableEntityType entityType)
{
if (typeof(IMayHaveOrganizationUnit).IsAssignableFrom(typeof(TEntity)))
{
return true;
}
return base.ShouldFilterEntity<TEntity>(entityType);
} protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>()
{
var expression = base.CreateFilterExpression<TEntity>();
if (typeof(IMayHaveOrganizationUnit).IsAssignableFrom(typeof(TEntity)))
{
Expression<Func<TEntity, bool>> mayHaveOUFilter = e => ((IMayHaveOrganizationUnit)e).OrganizationUnitId == CurrentOUId || (((IMayHaveOrganizationUnit)e).OrganizationUnitId == CurrentOUId) == IsOUFilterEnabled;
expression = expression == null ? mayHaveOUFilter : CombineExpressions(expression, mayHaveOUFilter);
} return expression;
} protected virtual int? GetCurrentUsersOuIdOrNull()
{
var userOuClaim = PrincipalAccessor.Principal?.Claims.FirstOrDefault(c => c.Type == "Application_OrganizationUnitId");
if (string.IsNullOrEmpty(userOuClaim?.Value))
{
return null;
} return Convert.ToInt32(userOuClaim.Value);
}
}
测试过滤器
要测试MayHaveOrganizationUnit筛选器,请创建一个组织单元,并将其用户ID设置为2(默认租户的管理用户的ID)和TenantID设置为1(默认租户的ID)。然后,在数据库中创建文档记录。用组织机构的OrganizationUnitId 设置默认租户管理员和已创建的文档。
在HomeController中从数据库获取数据:
[AbpMvcAuthorize]
public class HomeController : CustomFilterSampleControllerBase
{
private readonly IRepository<Document> _documentRepository; public HomeController(IRepository<Document> documentRepository)
{
_documentRepository = documentRepository;
} public ActionResult Index()
{
var documents = _documentRepository.GetAllList();
var documentTitles = string.Join(",", documents.Select(e => e.Title).ToArray()); return Content(documentTitles);
}
}
当您以host 用户身份登录时,应该会看到一个emtpy页面。但是,如果您以默认租户的管理员用户身份登录,您将看到以下文档标题:(以下丢失一张图片,请自行脑补,O(∩_∩)O哈哈~)
禁用筛选器
可以禁用如下筛选器:
[AbpMvcAuthorize]
public class HomeController : CustomFilterSampleControllerBase
{
private readonly IRepository<Document> _documentRepository;
private readonly IUnitOfWorkManager _unitOfWorkManager; public HomeController(IRepository<Document> documentRepository, IUnitOfWorkManager unitOfWorkManager)
{
_documentRepository = documentRepository;
_unitOfWorkManager = unitOfWorkManager;
} public ActionResult Index()
{
using (_unitOfWorkManager.Current.DisableFilter("MayHaveOrganizationUnit"))
{
var documents = _documentRepository.GetAllList();
var documentTitles = string.Join(",", documents.Select(e => e.Title).ToArray()); return Content(documentTitles);
}
}
}
在这种情况下,将从数据库检索所有文档记录,而不管登录用户OrganizationUnitId是什么。
翻译完成,但并不是我想要的功能 ┭┮﹏┭┮
最新文章
- goldengate初始化
- remove() 方法的兼容问题
- 转<;<;C#集合Dictionary中按值的降序排列
- CodeForces Round 199 Div2
- php获取某年某月的天数 【转】
- for循环语句以及迭代法和穷举法
- gitflow workflow
- Android相对布局(RelativeLayout)
- error MSB6006: “CL.exe”已退出
- 基于java callable及future接口解决生产者消费者问题
- poj2924---高斯求和
- mysql5.7.16安装
- C,java,Python,这些名字背后的江湖!
- 非root安装fastDFS及启动
- c#死锁示例代码
- Linux 用户与组
- 使用Typescript实现依赖注入(DI)
- vivado 下安装modelsim
- java实现导入excel功能
- JQEUERY案例