LinqToSQL足够强大吗? 是不是更强大但同样流畅的界面易于构建?

在上一个问题中,我询问ORM库是否是次优解决方案并获得了很多很好的反馈。 正如我对这个问题的进一步思考,我得出的结论是LinqToSQL(现在)的主要好处和LinqToEntities(未来)的承诺在于它们能够减少程序代码和SQL之间的“不匹配”。 鉴于LinqToSQL作为一种完整的数据查询语言的局限性,我不倾向于认为它的优势远不止于此,但我想了解其他人的意见。

首先,程序代码和SQL之间的“不匹配”是什么意思? 如果您曾经开发过数据库应用程序,那么您可能已经熟悉(并且厌倦)与数据库交互所需的步骤:设置所有参数,输入SQL命令,然后将预期结果手动转换回变量或代码中使用的实例。

通过使用“流畅”接口,lambda表达式,扩展方法等,LinqToSql使这变得更加容易。最终结果是,很容易将本机C#标量类型推送到数据检索调用中,并且很容易自动生成本机C#类实例。 以MS网站为例:

var q = from c in db.Customers where c.City == "London" select c; foreach (var cust in q) Console.WriteLine("id = {0}, City = {1}",cust.CustomerID, cust.City); 

很酷!

那么问题是什么?

好吧,正如我在顶部链接的文章中指出的那样,存在许多问题。 对我来说最大的一点是,任何能够在SQL方面做到最低限度的人都会立即遇到障碍。 不仅仅是因为SQL的替代品而创建的许多构造都不熟悉甚至是笨拙的(Group By?我们在LinqToSql中谈论丑陋 )。 更大的问题是有许多常见的构造本身不受支持(例如DateDiff)。 充其量,您可以将Linq的“逃出”并将SQL代码提交到Linq调用流中。

那么,简单地在C#(或VB)中嵌入SQL是不是更好,这种方式允许您自由地声明SQL,但是这也可以让您轻松参数嵌入并自动转换为本机类? 例如,如果我们在一个类中只实现六个函数,我们可以编写类似这样的东西(其中qry是我们的查询类的一个实例):

 var ListOfEnrollees = qry.Command("Select b.FirstName, b.LastName, b.ID From ClassEnroll a inner join Folder b on (a.ClientID = b.ClientID) ") .Where ("a.ClassID", classID) .AND() .Append("(DateDiff(d, a.ClassDate, @ClassDate) = 0) Order By LastName;") .ParamVal(classDate) .ReturnList(); 

Command只是简单地开始收集SQL语句, Where开始我们的SQL Where子句并输入第一个参数,在更多SQL上附加 大头钉ParamVal只输入一个参数值以匹配前一行中找到的SQL参数,而ReturnList确实转换为类所需的魔力。 请注意,这只是SQL:连接是微不足道的,支持DateDiff(或任何其他SQL构造)等。我们可以在SQL窗口中测试它,然后剪切并粘贴到我们的代码中,根据需要进行分解我们的参数。 这可不容易。

现在,上面显示的基本构造对我来说似乎非常简单,它可以使用我已有的SQL知识来处理任何 SQL构造。 我确实必须使用一些reflection和一些其他很酷的新C#3结构来使ReturnList(和类似的)调用工作,但总的来说,它非常简单。 我还添加了许多铃声和口哨声,使界面更流畅。 所以,这是我的问题,我希望听到社区的评论:

为什么我需要掌握LinqToEntities的复杂性甚至需要承担LinqToSql的开销? 难道这不是给我LinqToSql给我的一切以及更多吗? 除了奇异的Relational to Object映射之外,它是否甚至不包括LinqToEntities?

更新 :Hamish Smith认为,LINQ有朝一日可能是一个function完备的数据操作语言,如此强大,甚至不需要SQL。 这是一个重要的临界论点,我没有讨论,但我同意这一点。 我的立场的本质是,虽然LinqToSql有一些实际的优点,但它仍然远远没有达到Hamish的目标。 这是一个非常现实和显着的缺点。

Hamish还正确地说,我还在使用嵌入式SQL – 我还没有“解决”这个问题。 然而,对我来说,这是一个function,而不是一个错误。 SQL在选择和操作关系数据(毕竟,我们正在使用的工作)方面仍然要好得多,我希望能够用它来制作我的解决方案。 我认为嵌入式SQL不是问题,而是它与C#之间的阻抗不匹配。 然而,通过使用C#3的新的Linq启发function,我可以在很大程度上消除这种“阻抗不匹配”并获得两全其美的效果。

那么,简单地在C#(或VB)中嵌入SQL是不是更好,这种方式允许您自由地声明SQL,但是这也可以让您轻松参数嵌入并自动转换为本机类?

我通常做的非常接近这一点。 我在存储过程中编写SQL,因此我获得了真正SQL的自由。 在C#中,我使用Linq的DBML以自然的方式访问存储过程。 这感觉就像是两全其美。

对我来说,真正的解决方案看起来更简单:在C#代码中嵌入SQL并让编译器生成强类。 如果Visual Studio支持,我怀疑任何人都会使用其他任何东西。

(总是有人试图创建entity framework和“架构”而不需要SQL。据我所知,这从未真正起作用,只是因为结果难以维护且死得很慢。)

我认为LinqToSQL和LinqToEntities都是矫枉过正。 我采取了简约的方法。 我开发了一个使用DTO的DAL,并反映其属性以动态生成SQL。 它适用于我不需要的95%的情况,并且不想考虑SQL。 对于所有其他情况,我的DAL允许我编写我想要的任何SQL并返回DataSet,或者如果给定DTO,它将使用结果填充它。 它还允许使用相同的概念调用存储过程,返回DataSet或DTO。 它对我来说非常好用,如果我不想,我不需要看任何SQL。

linq2sql内置了分页支持,并且是强类型的。

如果您不使用实体跟踪,则可以避免使用实体跟踪。

您可以通过将sql函数包装到方法中来调用它们。

如果使用实体跟踪,则可以轻松批量处理多个数据操作调用(自动执行此操作,从而调用SubmitChanges)。 因此,您不要在数据库中执行15次以执行5次插入和10次更新。

当您想获得结构化信息时,它也很方便,例如:

 var someInfo = from s in Context.Somethings select new SomeInfo { AField = s.SomeColumn, RelatedStuff = s.RelatedInfo.Where(someconditionhere) }; 

我会说这不仅仅值得。 另请注意,如果您确实需要获得最佳性能,则可以编译表达式,它将与datareader速度匹配。

您在查询类中提出的建议是,您仍然将SQL直接嵌入到应用程序代码中。 您使用LINQ + ORM解决方案得到的是应用程序代码永远不会包含SQL。 您仍然存在不匹配和分散处理代码的注意力。 你在post中提到它:

我们可以在SQL窗口中测试它,然后剪切并粘贴到我们的代码中,根据需要进行分解以输入我们的参数。 这可不容易。

LINQ语法试图给我们的是查询作为代码中的一等公民。 有些东西是笨拙的,有些东西可能还不是很正确,但LINQ的既定目标是将查询和应用程序代码集成到没有不相交的地方。 听起来这不是你所追求的,所以可能将SQL嵌入到对编译器不透明的字符串文字中,运行时将更适合你。 我们知道它可以工作,我们已经做了多年。
另一个好处是LINQ语句不受供应商特定变化的影响(这是LINQ提供商的问题)。 您最终可能会将传递给qry.Command()的SQL字符串绑定到特定数据库。

var q = DataContext.ExecuteQuery (“SELECT * FROM etc”)通常做得很好。

目前, 我不是entity framework的粉丝 ,但4.0看起来有了很大改进。 我不确定它是否与Vista与Windows 7一样大,但绝对更好。

现在,我发现LINQ-to-SQL涵盖了我经常需要的大部分内容。 哎呀,即使我只是用它来连接存储过程而不必编写参数代码,这对我有利。 我发现CRUD的东西非常适合简单的正交数据操作。 对于更复杂的场景,我喜欢UDF等 – LINQ-to-SQL支持很好。

只要你将它隐藏在存储库中 ,你甚至都不会把自己画成一个角落。

Re datediff – 你看过SqlMethods吗?