首页 > 解决方案 > 实体框架 LinqKit 动态 where 相关数据的谓词

问题描述

该代码是 Alpha 版本,没有验证或错误管理......稍后会包含它。

我有一个非常简单的模型,其中包含两个相关实体:LocationCountry

public class UNCountry
{
    public int UNCountryId { get; set; }
    
    [Required]
    [MaxLength(2, ErrorMessage = "The field {0} only can contains a maximum of {1} characters lenght.")]
    [RegularExpression("[A-Z][A-Z]", ErrorMessage = "The field {0}, This code is formed by Two(2) capital letters")]
    public string Code { get; set; }
    
    [Required]
    [MaxLength(255, ErrorMessage = "The field {0} only can contains a maximum of {1} characters lenght.")]
    public string Name { get; set; }
}

public class UNLocation
{
    public int UNLocationId { get; set; }
    
    [MaxLength(1, ErrorMessage = "The field {0} only can contains a maximum of {1} characters lenght.")]
    public string UNChangeType { get; set; }      

    [Required]
    [MaxLength(5, ErrorMessage = "The field {0} only can contains a maximum of {1} characters lenght.")]
    [RegularExpression("[A-Z]{5}", ErrorMessage = "The field {0}, This code is formed by 5 capital letters")]
    public string Code { get; set; }

    [Required]
    [MaxLength(255, ErrorMessage = "The field {0} only can contains a maximum of {1} characters lenght.")]
    public string Name { get; set; }

    public int UNCountryId { get; set; }
    public UNCountry UNCountry { get; set; }
}

我有一个列出所有位置的应用程序,用户可以按任何列进行过滤,这是 Angular 中的通用组件视图,我希望所有列过滤器都是动态的。过滤器作为数组传入 JsonFilters 参数

[{name:"nameOfField1", value:"valueOfField1"},...], 

然后我用 LinqKit 和 PredicateBuilder 构造一个谓词,并在查询中使用谓词 .Where(predicate)。它完美地工作。

这是控制器中的初始代码

       var validFilter = new PaginationFilter(
                pF.PageNumber, pF.PageSize, pF.JsonFilters
        );
        var p = validFilter.CreateDynamicSearch<UNLocation>();
        //var b = PredicateBuilder.New<UNLocation>(true);
        //b = b.And(c => c.UNCountry.Name.Contains("Col"));
        var pagedData = await _context.UNLocations
            .Include(c => c.UNCountry)
            .Where(p)
            //.Where(d => d.UNCountry.Name.Contains("Col"))
            .OrderBy(x => x.UNLocationId)
            .Skip((validFilter.PageNumber - 1) * validFilter.PageSize)
            .Take(validFilter.PageSize)
            .ToListAsync();
        var totalRecords = await _context.UNLocations.CountAsync();
        return Ok(new PagedResponse<List<UNLocation>>(pagedData, validFilter.PageNumber, validFilter.PageSize,totalRecords));

我在过滤器参数中传递了字段名和值,一切正常,但是当我对国家/地区名称进行过滤时(字段名称是 UNCountry.Name),谓词在 UNLocations 上使用此字段名称失败,它在构造谓词的函数中失败,但是如果我直接在 Where 中使用(前面代码中的注释行 //.Where(d => d.UNCountry.Name.Contains("Col")) )它可以工作,我可以像这样解决问题,但是对于查询中具有更多相关数据字段的其他视图来说,它不会是动态的。

这是谓词生成函数:

public Expression<Func<T, bool>> CreateDynamicSearch<T>()
    {
        var predicate = PredicateBuilder.New<T>(true);
        foreach (ReqFilter filter in this.Filters)
        {
            var columnFilter = PredicateBuilder.New<T>(false);
            var param = Expression.Parameter(typeof(T), "a");

            string[] filterParts = filter.Name.Split(".");
            string filterName = filterParts[0];
            if (filterParts.Length == 1)
            {
                var prop = Expression.Property(param, filterName);
                var call = Expression.Call(prop, "Contains", new Type[0], Expression.Constant(filter.Value));
                columnFilter = columnFilter.Or(Expression.Lambda<Func<T, bool>>(call, param));
                predicate = predicate.And(columnFilter);
            }
            else
            {
                 var prop = Expression.Property(param, filter.Name);

                var call = Expression.Call(prop, "Contains", new Type[0], Expression.Constant(filter.Value));
                columnFilter = columnFilter.Or(Expression.Lambda<Func<T, bool>>(call, param));
                predicate = predicate.And(columnFilter);

            }
        }
        return predicate;
    }

如果我使用 UNLocation 的普通字段(如代码或名称 byExample [{code:"MIA"},name:"MI"])传递过滤器,则此代码运行良好,但如果我发送列名,谓词构造函数将失败相关的 UNCountry Name byExample [{UNCountry.Name:"United States"}],我重复如果我在设计时代码中编写 Where 代码,它可以工作,但我需要具有 mor 灵活性,并在谓词中生成。有可能或如何做到这一点?提前谢谢,原谅我的英语。

标签: entity-frameworkpredicatebuilderlinqkit

解决方案


推荐阅读