在之前的一个问题中,我询问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启发功能,我可以在很大程度上消除这种“阻抗不匹配”并获得两全其美的效果。
答案 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
吗?