简体   繁体   English

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

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

I have got the following expression that works with mockup data - hereby not using Entity Framework: 我有以下适用于模型数据的表达式-从而不使用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))
 );

} }

However, I get this famous exception when I try to insert this expression in the where clause of my repository method (using Entity Framework): 但是,当我尝试将这个表达式插入到存储库方法的where子句中(使用Entity Framework)时,出现了这个著名的异常:

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

I suspect this has something to do with a parameter called filterValuesForUser, which is a collection of a complex (ie custom) type. 我怀疑这与名为filterValuesForUser的参数有关,该参数是复杂(即自定义)类型的集合。

Is this behavior even possible in Entity Framework where I do a subquery that is not directly related to Entity Framework? 在执行与实体框架不直接相关的子查询的实体框架中,这种行为甚至可能发生? What I want to achieve here is to query on a subset of a custom list for each group in the query. 我要在这里实现的是针对查询中每个组的自定义列表的子集进行查询。

Any solutions for this or other workarounds? 这个或其他解决方法有什么解决方案? I'd like to minimize the amount of database calls, preferrably limit it to just one. 我想最小化数据库调用的数量,最好将它限制为一个。

The exact query you are asking for is impossible with LinqToEF (due to limitation of SQL). LinqToEF无法实现您要查询的确切查询(由于SQL的限制)。 But fear not. 但是不要担心。 It is possible to salvage your problem with a slight tweaking. 稍加调整即可解决您的问题。

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

}

Types and Extension methods expanded for clarity. 为了清楚起见,扩展了类型和扩展方法。

In addition to Aron's answer, I used the PredicateBuilder utility in the LinqKit assembly to generate 1 expression rather than multiple and separate expresssions. 除了Aron的答案外,我还使用LinqKit程序集中的PredicateBuilder实用程序生成1个表达式,而不是多个单独的表达式。 This also avoids doing multiple database calls. 这也避免了执行多个数据库调用。

Here is how you can achieve this (pseudo-code): 这是实现此目的(伪代码)的方法:

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

I'm still having issues with getting this working in my repository but that has something do with something blocking AsExpandable() from working properly. 我仍然无法在存储库中正常工作,但这与阻止AsExpandable()正常工作有关。

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

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