所以我最近发现你可以通过指定扩展方法而不是表达式Func<T, TResult>
来强制实体框架不要将你的投影转换为 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 数据库可以执行的操作,但是根据这篇文章Func 谓词不会被翻译。
一旦我完成了这项工作,创建以下扩展方法并没有太大的飞跃:
public static IQueryable<T> Materialize<T>(this IQueryable<T> q)
{
return q.Select(new Func<T, T>(t => t)).AsQueryable();
}
所以我的问题是 - 使用它时有什么我应该警惕的陷阱吗?是否存在性能影响 - 要么将此无操作投影注入查询管道,要么导致 EF 不将.Where()
子句发送到服务器,从而通过线路发送所有结果?
目的是仍然使用一种.Where()
方法来过滤服务器上的结果,然后使用.Materialize()
before.Select()
以便提供程序不会尝试将投影转换为 SQL Server:
return Context.Record
.Where(r => // Some filter to limit results)
.Materialize()
.Select(r => // Some projection to DTO, etc.);