繁体   English   中英

存储库中实体框架中where子句中的复杂表达式

[英]Complex expression in where clause in Entity Framework in repository

我有以下适用于模型数据的表达式-从而不使用Entity Framework:

 public static Expression<Func<Resource, bool>> FilterResourcesByUserCriteria(IEnumerable<FilterValue> filterValuesForUser)
    {
      Expression<Func<Resource, bool>> filter = (resource) =>
      // Get filter values for the current resource in the loop

     resource.ResourceFilterValues

     // Group filter values for user
    .GroupBy(filterValue => filterValue.FilterValue.FilterGroup.Id)

    // Each group must fulfill the following logic
    .All(filterGroup =>

    // For each filter group, only select the user values from the same group
    filterValuesForUser
    .Where(filterValueForUser => filterValueForUser.FilterGroup.Id == filterGroup.Key)
    .Select(filterValueForUser => filterValueForUser.FilterValue1)

     // Each group must at least one value in the sublist of filter values of the current user
    .Any(filterValueForUser => filterGroup
      .Select(resourceFilterValue => resourceFilterValue.FilterValue.FilterValue1)
      .Any(x => x == filterValueForUser))
 );

}

但是,当我尝试将这个表达式插入到存储库方法的where子句中(使用Entity Framework)时,出现了这个著名的异常:

Unable to create a constant value of type. Only primitive types or enumeration types are supported in this context.

我怀疑这与名为filterValuesForUser的参数有关,该参数是复杂(即自定义)类型的集合。

在执行与实体框架不直接相关的子查询的实体框架中,这种行为甚至可能发生? 我要在这里实现的是针对查询中每个组的自定义列表的子集进行查询。

这个或其他解决方法有什么解决方案? 我想最小化数据库调用的数量,最好将它限制为一个。

LinqToEF无法实现您要查询的确切查询(由于SQL的限制)。 但是不要担心。 稍加调整即可解决您的问题。

public static Expression<Func<Resource, bool>> FilterResourcesByUserCriteria(FilterValue filterValueForUser)
{
    //I assume you can write this part yourself.
}

public IQueryable<Resource> GetResources()
{
    IQueryable<Resource> resources = _context.Resources;
    IEnumerable<FilterValue> filterValuesForUser  = GetFilterValues();

    IEnumerable<IQueryable<Resource>> queries = from filter in filterValuesForUser
                                                let filterExp = FilterResourcesByUserCriteria(filter)
                                                select resources.Where(filterExp);
    return Enumerable.Aggregate(queries, (l, r) => Queryable.Concat(l, r));

}

为了清楚起见,扩展了类型和扩展方法。

除了Aron的答案外,我还使用LinqKit程序集中的PredicateBuilder实用程序生成1个表达式,而不是多个单独的表达式。 这也避免了执行多个数据库调用。

这是实现此目的(伪代码)的方法:

public IQueryable<Resource> GetResources()
{      
       MyContext ctx = new MyContext ();
       IEnumerable<Expression<Func<Resource, bool>>> queries =
            filterValuesForUser.GroupBy(x => x.FilterGroup)
            .Select(filter => SecurityFilters.FilterResourcesByUserCriteriaEF(filter.Select(y => y.FilterValue1)))
            .Select(filterExpression => { return filterExpression; });

   Expression<Func<Resource, bool>> query = PredicateBuilder.True<Resource>();
        foreach (Expression<Func<Resource, bool>> filter in queries)
        {
            query = query.And(filter);
        }

        return ctx.Resources.AsExpandable().Where(query);
}      


public static Expression<Func<Resource, bool>> FilterResourcesByUserCriteriaEF(IEnumerable<string> filterValuesForUser)
{
        // From the resource's filter values, check if there are any present in the user's filter values
        return (x) => x.ResourceFilterValues.Any(y => filterValuesForUser.Contains(y.FilterValue.FilterValue1));
}

我仍然无法在存储库中正常工作,但这与阻止AsExpandable()正常工作有关。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM