linq - 这个扩展方法是否有效地实现了我的 IQueryable?

标签 linq entity-framework-5 deferred-execution

所以我最近发现,您可以通过指定Func<T, TResult>来强制 Entity Framework 不将您的投影转换为SQL。到.Select()扩展方法而不是表达式。当您想要转换查询的数据时,这非常有用,但该转换应该在代码中而不是数据库中进行。

例如,当使用 EF5 的新 Enum 支持并尝试将其投影到 DTO 中的字符串属性时,这会失败:

results.Select(r => new Dto { Status = r.Status.ToString() })

这会起作用:

results.Select(new Func<Record, Dto>(r => new Dto { Status = r.Status.ToString() }));

因为在第一种(表达式)情况下,EF 无法弄清楚如何将 Status.ToString() 转换为 SQL 数据库可以执行的操作,但根据this article Func 谓词未翻译。

一旦我完成了这个工作,创建以下扩展方法就没有太大的飞跃:

public static IQueryable<T> Materialize<T>(this IQueryable<T> q)
{
    return q.Select(new Func<T, T>(t => t)).AsQueryable();
}

所以我的问题是 - 使用它时有什么我应该警惕的陷阱吗?是否会对性能产生影响 - 要么将此不执行任何操作的投影注入(inject)查询管道,要么导致 EF 不发送 .Where()子句发送到服务器,从而通过网络发送所有结果?

目的是仍然使用 .Where()方法来过滤服务器上的结果,但随后使用 .Materialize()之前.Select()这样提供程序就不会尝试将投影转换为 SQL Server:

return Context.Record
    .Where(r => // Some filter to limit results)
    .Materialize()
    .Select(r => // Some projection to DTO, etc.);

最佳答案

简单地使用AsEnumerable应该做同样的事情:

return Context.Record
              .Where(r => // Some filter to limit results)
              .AsEnumerable() // All extension methods now accept Func instead of Expression
              .Select(r => // Some projection to DTO, etc.);

您的 Materialize 方法中也没有理由返回到 IQueryable,因为它不再是转换为另一个查询的真正的 IQueryable。它只是 IEnumerable

就性能而言,你应该没问题。实现之前的所有内容都在数据库中进行评估,而实现之后的所有内容都在代码中进行评估。此外,在您和我的示例查询中,查询仍然延迟执行 - 在枚举查询之前它不会执行。

关于linq - 这个扩展方法是否有效地实现了我的 IQueryable?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12387180/

相关文章:

C# 如何按具有相同属性值的对象对列表进行分组

asp.net-mvc - 使用 Entity Framework 6 的 mvc4 中的单个或多个 DbContext 文件

c# - 使用 DbContext 在一个文件中生成 POCO 类

c# - IEnumerable 的多重枚举 - StackOverflowException

c# - 在 "using"语句中使用 yield 时,Dispose 何时发生?

linq - NHibernate 3.x 在组合 LINQ 分页、多对多和子选择获取时删除子实体

c# - 将列表值拆分为逗号分隔的字符串

c# - 按 linq 中的特殊枚举值排序列表

sql - Entity Framework -属性IN子句用法

c# - yield 在 lock 语句中返回