如何创建动态Linq表达式

6tqwzwtp  于 2022-12-06  发布在  其他
关注(0)|答案(2)|浏览(145)

我在哪里可以了解到如何创建一个“动态”linq表达式?我需要将其转换为动态的东西,因为当在实体框架的OnModelCreating中执行代码时,currentUser为空。我正在尝试创建一个全局查询过滤器。

User currentUser = currentUserService.GetUser();
IPermissionService permissionService = DependencyResolver.Current.GetService<IPermissionService>();

var allowedToSee = Entities.Where(e => permissionService.HasPermission(e, currentUser).View);
modelBuilder.Entity<Audit>().HasQueryFilter(x => allowedToSee.Contains(x.EntityType));

这是审计类:

public class Audit
    {
        // Information about changes

        public virtual Entity EntityType { get; set; }
    }

其他动态linq表达式的示例:

protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        foreach (var entityType in modelBuilder.Model.GetEntityTypes())
        { 
            //If the actual entity is an auditable type. 
            if(typeof(Auditable).IsAssignableFrom(entityType.ClrType))
            {
                //This adds (In a reflection type way), a Global Query Filter
                //https://docs.microsoft.com/en-us/ef/core/querying/filters
                //That always excludes deleted items. You can opt out by using dbSet.IgnoreQueryFilters()
                var parameter = Expression.Parameter(entityType.ClrType, "p");
                var deletedCheck = Expression.Lambda(Expression.Equal(Expression.Property(parameter, "DateDeleted"), Expression.Constant(null)), parameter);
                modelBuilder.Entity(entityType.ClrType).HasQueryFilter(deletedCheck);
            }
        }
        
        base.OnModelCreating(modelBuilder);
    }
ojsjcaue

ojsjcaue1#

假设您有下列DbContext,且AllowedToSee属性已正确实作,则ApplyAuditFilters应该会将查询筛选套用至所有Audit子代。

public class MyDbContext : DbContext
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        ApplyAuditFilters(modelBuilder);

        base.OnModelCreating(modelBuilder);
    }

    // implement this property
    public IEnumerable<Entity> AllowedToSee => throw new NotImplementedException();

    private void ApplyAuditFilters(ModelBuilder modelBuilder)
    {
        var types = modelBuilder.Model.GetEntityTypes()
            .Where(et => typeof(Audit).IsAssignableFrom(et.ClrType));

        var thisExpression = Expression.Constant(this);

        // this.AllowedToSee
        var allowedToSeeExpr = Expression.Property(thisExpression, nameof(AllowedToSee));

        foreach (var et in types)
        {
            var param = Expression.Parameter(et.ClrType, "e");

            // e.EntityType
            var filterPropertyExpr = Expression.Property(param, nameof(Audit.EntityType));

            // this.AllowedToSee.Contains(e.EntityType)
            var filterBody = Expression.Call(typeof(Enumerable), nameof(Enumerable.Contains), new[] { typeof(Entity) },
                allowedToSeeExpr, filterPropertyExpr);

            // e => this.AllowedToSee.Contains(e.EntityType)
            var queryFilter = Expression.Lambda(filterBody, param);

            modelBuilder.Entity(et.ClrType).HasQueryFilter(queryFilter);
        }
    }

    ... // other members
}
myss37ts

myss37ts2#

如果您需要“动态”linq,我建议使用System.Linq.Dynamic.Core
这是documentation for it
但是,我不确定这是否是您的最佳解决方案,但是如果您想动态生成linq表达式,那么这是一个很好且简单的方法。

相关问题