扩展EF4 SQL生成

时间:2010-06-08 14:03:33

标签: .net entity-framework extension-methods entity-framework-4

我们在一个相当大的系统中使用EF4,偶尔会遇到问题,因为EF4无法将某些表达式转换为SQL。目前,我们要么需要做一些花哨的步法(DB / Code),要么只接受性能命中并允许查询在内存中执行。

毋庸置疑,这些都不是理想的,我们有时不得不使用的黑客技术降低了可读性/可维护性。

我们理想的是扩展EF4 SQL提供程序的SQL生成功能的方法。显然有一些像.Net方法调用这样的东西总是必须是客户端的,但是一些功能,比如日期比较(例如[Linq到Entities的分组)应该是可行的。

我用Google搜索了,但也许我使用了错误的术语,因为我得到的是有关EF4 SQL生成新功能的信息。

对于这样一个灵活且可扩展的框架,如果不可能,我会感到惊讶。在我的脑海中,我想象从[SQL 2008]提供程序继承并扩展它以处理表达式树中的其他表达式/类似物,它被转换为SQL。

任何帮助/指示赞赏。

我们正在使用VS2010 Ultimate,.Net 4(非客户端配置文件)和EF4。该应用程序位于ASP.Net中,并且在64位环境中运行,以防它发挥作用。

更新:回应一些澄清请求;

我们使用的是代码优先方法,并有一个控制台应用程序,可以创建数据库并填充一些参考表。

我宁愿远离存储过程,除非它们也可以以类似的方式生成 - 目前,根据需要生成新版本的数据库,并且单独的进程迁移/同步数据。 我们目前对数据库使用实体所做的一切。我承认我无法给出一个很好的理由,但在这种情况下运行SQL脚本来生成存储过程感觉不对 - 但如果我弄错了,请纠正我。

关于特定情况,我担心如果不经过长时间的繁文缛节练习,我就无法从我们的代码中提供一个 - link mentioned above就是我们的一个很好的例子。重新努力完成。在此示例中,实现了允许日期算术的机制:

DateTime firstDay = GetFirstDayOfFirstWeekOfYear();
var userTimes = from t in context.TrackedTimes
                group t by new {t.User.UserName, WeekNumber = (t.TargetDate - firstDay).Days / 7} into ut
                select new
                {
                    UserName = ut.Key.UserName,
                    WeekNumber = ut.Key.WeekNumber,
                    Minutes = ut.Sum(t => t.Minutes)
                };

我可以看到一种方法可以单独使用SQL来完成,但不能使用LINQ-To-Entities(服务器端)来实现。

2 个答案:

答案 0 :(得分:9)

我建议首先查看EntityFunctions(通用)或SqlFunctions(仅限SQL Server),它们在正常的LINQ to Entities查询中提供了大量内置数据库功能。如果这还不够,可以使用EdmFunctionAttribute映射内置数据库函数或用户定义的存储过程。第三种选择是尝试使其作为实体SQL查询工作。

您建议的最后一个解决方案 - 编写EF提供商 - 非常重要。可以编写一个包装现有SQL提供程序的EF提供程序,但您必须至少将一些表达式树更改为Entity SQL。非常简单的EF提供程序包装器已在MSDN Code上发布。不过,我会把这视为最后的手段。

答案 1 :(得分:1)

从基于.NET的LINQ查询到SQL的转换由 LINQ To Entities Provider 处理。我不认为核心翻译/编译过程非常复杂,是可扩展的。您必须从头开始编写自己的提供程序。

我还没有遇到任何可以在SQL中表示的查询,这些查询无法在LINQ中表示。如果您确实有一个难以作为LINQ查询编写的查询,您是否考虑过使用存储过程?如果您能提供一些不会转换的查询示例,将会有所帮助。

更新:

另一种选择是创建使用自定义表达式形成查询的高级扩展方法。这是一个很好的例子,模拟Contains()函数来执行“where in”类型查询:

'Contains()' workaround using Linq to Entities?