【问题标题】:LINQ to Entities Does not Support Invoke in Entity FrameworkLINQ to Entities 不支持实体框架中的调用
【发布时间】:2016-02-02 10:09:53
【问题描述】:

下面是我必须使用表达式的函数,但我认为 Entity Framework 不允许这样做。我已经在 Linq-to-SQL 中使用了这个函数并且它正在工作。我也尝试过使用 LinqKit,因为这是我在许多答案中发现的,但错误仍然存​​在。

public static IList<SelectListItem> From<T>(IQueryable<T> Source, Expression<Func<T, object>> Value, Expression<Func<T, string>> Text)
{
    var q = from T item in Source
            select new SelectListItem()
            {
                Text = Text.Compile()((item)),
                Value = Value.Compile()((item)).ToString()
            };
    return q.ToList();
}

当我通过将List&lt;T&gt; 转换为IQueryable 来提供源时,它可以工作。

【问题讨论】:

  • 你确定它在 LinqToSQL 中工作吗?你看过生成的 SQL 了吗?
  • 但是,如果你真的想解决这个问题,这很容易。步骤是here。只有第 3 步会有所不同。
  • @Aron LINQ to SQL 对于无法转换为 SQL 的构造比 EF 更宽容,而是在客户端上简单地执行它们。如果它确实“工作”它一点也不会让我感到惊讶,并且 SQL 应该表明它只是请求整个 item
  • LINQ to SQL 正在做的正是你所做的,但不会告诉你——它将所有内容加载到内存中,然后将查询转换为 LINQ to Objects。这可以消除性能,因为它可以在内存中加载 很多 不需要的对象。 EF 不允许这样做并立即警告您。
  • @hvd 这正是我要说的......

标签: c# entity-framework linq


【解决方案1】:

您可以像这样使用LinqKit 解决您的问题:

public static IList<SelectListItem> From<T>(
    IQueryable<T> Source,
    Expression<Func<T, object>> Value,
    Expression<Func<T, string>> Text)
{
    var q = from T item in Source.AsExpandable()
            select new SelectListItem()
            {
                Text = Text.Invoke(item),
                Value = Value.Invoke(item).ToString()
            };

    return q.ToList();
}

AsExpandable 允许在查询执行之前扩展表达式。

当我像这样在客户表上测试上述代码时:

var result =
    From(
        context.Customers,
        x => x.CustomerId,
        x => x.Name);

这是在 SQL 服务器上执行的 SQL:

SELECT 
    [Extent1].[CustomerId] AS [CustomerId], 
    [Extent1].[Name] AS [Name], 
     CAST( [Extent1].[CustomerId] AS nvarchar(max)) AS [C1]
    FROM [dbo].[Customers] AS [Extent1]

【讨论】:

  • 我已经尝试过 LInqKit,但在这种情况下它也无法正常工作,错误是“无法将 'System.Linq.Expressions.InstanceMethodCallExpressionN' 类型的对象转换为 'System.Linq.Expressions.LambdaExpression' 。”
  • 您是否按原样使用我的答案中的代码?我已经在本地测试了这段代码,它可以工作。你能展示一下你目前拥有的代码吗?
【解决方案2】:

您需要使用System.Linq.Expressions 构建整个表达式。

这是一个执行此操作的函数(我对类似问题 Expression to convert IQueryable<t> int List<SelectListItem> 的回答的修改版本):

public static class Utils
{
    public static IList<SelectListItem> ToSelectList<TSource, TValue>(this IQueryable<TSource> source, Expression<Func<TSource, TValue>> valueSelector, Expression<Func<TSource, string>> textSelector)
    {
        var itemValue = valueSelector.Body;
        if (itemValue.Type != typeof(string))
            itemValue = Expression.Call(itemValue, itemValue.Type.GetMethod("ToString", Type.EmptyTypes));
        var itemText = textSelector.Body.ReplaceParameter(textSelector.Parameters[0], valueSelector.Parameters[0]);
        var targetType = typeof(SelectListItem);
        var selector = Expression.Lambda<Func<TSource, SelectListItem>>(
            Expression.MemberInit(Expression.New(targetType),
                Expression.Bind(targetType.GetProperty("Value"), itemValue),
                Expression.Bind(targetType.GetProperty("Text"), itemText)
            ), valueSelector.Parameters);
        return source.Select(selector).ToList();
    }

    static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target)
    {
        return new ParameterExpressionReplacer { source = source, target = target }.Visit(expression);
    }

    class ParameterExpressionReplacer : ExpressionVisitor
    {
        public ParameterExpression source;
        public Expression target;
        protected override Expression VisitParameter(ParameterExpression node)
        {
            return node == source ? target : base.VisitParameter(node);
        }
    }
}

请注意,我已经更改了名称,添加了第二个通用参数以能够传递未修改的值类型,并使其成为扩展方法,因此可以像这样使用它

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
}

var result = db.Persons.ToSelectList(p => p.Id, p => p.Name);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多