Article Translations: ABP how to add data filters EF core in

Original Address: https: //aspnetboilerplate.com/Pages/Documents/Articles%5CHow-To%5Cadd-custom-data-filter-ef-core

 

In this article, I will explain how to add custom data filter in the EF core.

We will OrganizationUnit create a filter, and from the IMayHaveOrganizationUnitinterface inheritance entity, automatically filtered according to the user's login organizational unit.

We will use asp.net asp.net core and query templates. You can create a project on https://aspnetboilerplate.com/templates, and apply the following steps to view the operation of custom organizational unit filters.

 

Creating and updating entity

Creating entity

Create an entity called inherited from IMayHaveOrganizationUnit Document Interface (IMayHaveOrganizationUnit interfaces are defined in the framework of abp).

public class Document : Entity, IMayHaveOrganizationUnit
{
    public string Title { get; set; }

    public string Content { get; set; }

    public long? OrganizationUnitId { get; set; }
}

  Add Document entity in your DbContext

 

Update User class

Add OrganizationUnitId to user.cs. We will use OrganizationUnitId field user to filter the Document entity.

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

  

Adding migration

Use the command add migration add to migrate and run update database to apply the changes to the database.

 

Create a Claim

We need Claim stored in the user's login OrganizationUnitId, so that you can get it to filter IMayHaveOrganizationUnit entities in DbContext. To this end, rewrite CreateAsync method UserClaimsPrincipalFactory class and add the following to the logged-in user OrganizationUnitId statement.

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

  

Sign filter

Before the screening DbContext entities, we will register the filter, in order to disable it in some cases the code.

Sign up filters PreInitialize method YourProjectNameEntityFrameworkModule in order to obtain it from the current work unit manager.

public override void PreInitialize()
{
    ...

    //register filter with default value
    Configuration.UnitOfWork.RegisterFilter("MayHaveOrganizationUnit", true);
}

  

Configuration DbContext

We need to use the value OrganizationUnitId to filter IMayHaveOrganizationUnit entity DbContext in.

To do this, first add the following fields in DbContext in:

protected virtual int? CurrentOUId => GetCurrentUsersOuIdOrNull();

A method as defined in GetCurrentUsersOuIdOrNull DbContext and use propert implantation IPrincipalAccessor injected into the 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);
	}	
}

  After that, let's add a property to the DbContext, for if MayHaveOrganizationUnit filter enabled.

protected virtual bool IsOUFilterEnabled => CurrentUnitOfWorkProvider?.Current?.IsFilterEnabled("MayHaveOrganizationUnit") == true;

  

AbpDbContext defines two data associated with the filter method. One is ShouldFilterEntity, and the other is CreateFilterExpression. ShouldFilterEntity method determines whether to filter entities. CreateFilterExpression way to create a filter expression to filter entities.

To filter inherited from IMayHaveOrganizationUnit entity, we need to override these two methods.

First, the method shown below override ShouldFilterEntity;

protected override bool ShouldFilterEntity<TEntity>(IMutableEntityType entityType)
{
    if (typeof(IMayHaveOrganizationUnit).IsAssignableFrom(typeof(TEntity)))
    {
        return true;
    }

    return base.ShouldFilterEntity<TEntity>(entityType);
}

Then, rewriting CreateFilterExpression method, as shown below;

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

  The following is the final version of 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);
    }
}

  

Test filter

To test MayHaveOrganizationUnit filter, create an organizational unit and set its user ID is 2 (default administrative user's tenant ID) and TenantID set to 1 (the default tenant ID). Then, create a document recorded in the database. The default tenant administrator and documents that have been created with OrganizationUnitId setting organization.

Get data from the database in the 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);
    }
}

When you log on to host user, you should see a emtpy page. However, if you default tenant administrator user logged in, you will see the following document title :( missing a picture, make up your own brain, O (∩_∩) O ~ ha ha)

 

Disable the filter

You can disable the following filters:

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

  In this case, all the documents retrieved from the database records, regardless of what the user login OrganizationUnitId Yes.

Translated, but not what I wanted function ┭┮﹏┭┮

Guess you like

Origin www.cnblogs.com/bamboo-zhang/p/11765037.html