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

时间:2009-03-12 18:57:53

标签: c# sql database linq-to-sql

在之前的一个问题中,我询问ORM libraries were suboptimal solutions是否得到了很多很好的反馈。正如我对这个问题的进一步思考,我得出结论,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);

非常酷!

那么问题是什么?

好吧,正如我在顶部链接的文章中指出的那样,存在许多问题。对我来说,最大的 showstopper是那些在SQL方面能力最低的人会立即遇到障碍。不仅仅是因为SQL的替代品而创建的许多构造都不熟悉甚至笨拙(Group By?我们在LinqToSql中谈论 Ugly )。更大的问题是有许多常见的结构本身不受支持(例如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<EnrollListMemberData>();

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

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

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

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

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

6 个答案:

答案 0 :(得分:2)

  

所以,简单地嵌入是不是更好   C#(或VB)中的SQL允许的方式   你可以自由地陈述你的SQL   还为您提供简单的参数嵌入   并自动转换为原生   类?

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

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

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

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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速度匹配。

答案 3 :(得分:1)

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

  

我们可以在SQL窗口中测试它   然后剪切并粘贴到我们的代码中,   分解为适当进入   我们的参数。这可不容易。

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

答案 4 :(得分:1)

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

答案 5 :(得分:0)

目前,I'm not a fan的实体框架,但4.0看起来有了很大改进。我不确定它是否与Vista与Windows 7一样大,但肯定更好。

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

只要你hide it in a repository,你甚至不会把自己画成一个角落。

Re datediff - 你看过SqlMethods吗?