【问题标题】:Complex expression in where clause in Entity Framework in repository存储库中实体框架中 where 子句中的复杂表达式
【发布时间】:2015-09-16 06:10:38
【问题描述】:

我有以下适用于模型数据的表达式 - 特此不使用实体框架:

 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 子句中时(使用实体框架),我得到了这个著名的异常:

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

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

在我执行与实体框架不直接相关的子查询的实体框架中,这种行为是否可能?我想在这里实现的是查询查询中每个组的自定义列表的子集。

针对此或其他变通办法的任何解决方案?我想尽量减少数据库调用的数量,最好将其限制在一个。

【问题讨论】:

  • -1 查询之外的对象太多。捕获的是什么并不明显。显示更多上下文代码。
  • @Aron 我觉得这里没有太多,只是这个filterValuesForUser在外面准备好了,我觉得这里的代码已经足够了。
  • @Hopeless 我真的很难确定filterValuesForUser 是被捕获的IEnumerable
  • @Aron 是的,这对我来说也很难,但仔细扫描后我们可以发现它。
  • 嗨,Aron,我可以想象。我已经更新了代码摘录。我认为 filterValuesForUser 导致了问题,因为它与表达式中的项目没有直接关系,而是与外部集合相关。

标签: c# entity-framework expression where-clause


【解决方案1】:

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

}

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

【讨论】:

  • 这是正确的方法,但最困难的部分实际上是您认为 OP 可以自己编写的部分。
  • @Hopeless 我同意。但是 OP 设法达到了他在表达式树上所做的那样,所以改变它并没有太大的飞跃。
  • 谢谢,我会试一试。它需要对我的存储库进行一些调整才能使其正常工作,但它看起来像是要走的路。
【解决方案2】:

除了 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() 正常工作有关。

【讨论】:

    猜你喜欢
    • 2014-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-31
    相关资源
    最近更新 更多