【问题标题】:How to use a Func in an expression with Linq to Entity Framework?如何在 Linq to Entity Framework 的表达式中使用 Func?
【发布时间】:2013-09-27 13:50:15
【问题描述】:

我正在尝试编写一个 linq to entity 扩展方法,该方法采用 Func 选择属性 ID 并将其与 id 列表进行比较。

public class A
{
    public int AId { get; set; }
}

public class B
{
    public int BId { get; set; }
}

扩展方法

public static IQueryable<T> WithId<T>(this IQueryable<T> entities,
    Func<T, int> selector, IList<int> ids)
    {
        Expression<Func<T, bool>> expression = x => ids.Contains(selector(x));
        return entities.Where(expression); // error here (when evaluated)
    }

调用方法

var ids = new List<int> { 1, 2, 3 };
DbContext.EntityAs.WithId(e => e.AId, ids);
DbContext.EntityBs.WithId(e => e.BId, ids);

我遇到的问题是它试图调用实体框架中不允许的函数。

如何使用属性选择器 (Func) 来评估查询?

【问题讨论】:

  • 您可以在 EF 查询中调用的代码范围受到它仍然需要在 SQL 中翻译的事实的限制。在您的情况下,EF 不知道如何自动翻译 IList。
  • 我不确定你是否正确。 DbContext.EntityAs.Where(e => ids.Contains(e.Id)) 被EF正确翻译。我只是想创建一个可重用的函数,以便我可以定义要选择的属性。
  • 因为 EF 知道如何在 enumerable 的情况下执行 select x where x in (1,2,3) 或在另一个实体关系的情况下执行 select x where x in (select y)。在你的情况下,EF 需要编译类似select x where x in (select y where F(y) in (F(1),F(2),...)) 的东西。虽然可以手动执行此操作,但 EF 只是不支持这种情况 yet
  • 它应该只评估选择 x 其中 F(y) in (1,2,3) 其中 F(y) 将被评估为 x.AId 或 x.BId?有没有办法在表达式树中手动构建它?

标签: c# linq entity-framework expression func


【解决方案1】:

您必须传递 Expression&lt;Func&lt;T, int&gt;&gt; 而不是 Func&lt;T, int&gt; 并自己构建完整的表达式。这样就可以了:

public static IQueryable<T> WithId<T>(this IQueryable<T> entities,
    Expression<Func<T, int>> propertySelector, ICollection<int> ids)
{
    var property =
        (PropertyInfo)((MemberExpression)propertySelector.Body).Member;

    ParameterExpression parameter = Expression.Parameter(typeof(T));

    var expression = Expression.Lambda<Func<T, bool>>(
        Expression.Call(
            Expression.Constant(ids),
            typeof(ICollection<int>).GetMethod("Contains"), 
            Expression.Property(parameter, property)), 
        parameter);

    return entities.Where(expression);
}

当您在使用 O/RM 时尝试保持代码 DRY 时,您经常不得不摆弄表达式树。这里是another fun example

【讨论】:

  • 太棒了。我正在试验如何从blogs.msdn.com/b/miah/archive/2009/02/06/…stackoverflow.com/questions/820896/… 构建表达式树,但不知道如何构建集合/列表包含。谢谢!
  • @DavidLiddle:我告诉你一个小秘密:我只是编写 LINQ 查询,编译并打开 Reflector 以查看 C# 编译器生成的内容。您也可以在调试器中看到此信息,但 Reflector 更容易。
  • 你能举一个“简单地编写 LINQ 查询”的例子吗?使用 ILSpy 我只看到了我写的确切的 LINQ 查询!
  • @DavidLiddle:我不熟悉 ILSpy,但使用 Reflector 我可以选择“优化”进行代码反编译。我将此选项从“.NET 4.0”调低到“.NET 2.0”,以查看表达式是如何构造的(因为 Reflector 足够聪明,可以重构 LINQ 查询)。 ILSpy 可能有类似的功能。
  • @hbob 将表达式包装在 Expression.Not 中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-27
相关资源
最近更新 更多