LINQ最难或最被误解的方面是什么?

背景:在接下来的一个月里,我将做三次关于或至少包括LINQ的演讲,在C#的背景下。我想知道哪些话题值得花相当多的精力,这取决于人们可能很难理解哪些话题,或者他们可能有错误的印象。我不会具体讨论LINQSQL或实体框架,只是作为如何使用表达式树(通常是IQueryable)远程执行查询的示例。

那么,你发现LINQ有什么困难?在误解方面你看到了什么?例子可能是以下任何一个,但请不要限制自己!

  • C#编译器如何处理查询表达式
  • Lambda表达式
  • 表达式树
  • 扩展方法
  • 匿名类型
  • IQueryable
  • 延迟执行与立即执行
  • 流与缓冲执行(例如,OrderBy被延迟但被缓冲)
  • 隐式类型局部变量
  • 读取复杂的泛型签名(例如可列举的。加入)
50571 次浏览

延迟加载。

延迟执行

不仅有LINQSQL,而且这些特性不仅仅是嵌入在语言中的SQL解析器。

我认为Lambda表达式可以解析表达式树和匿名委托,所以你可以将相同的声明性lambda表达式传递给IEnumerable<T>扩展方法和IQueryable<T>扩展方法。

我认为你应该更详细地关注LINQ中最常用的特性——Lambda表达式和匿名类型,而不是浪费时间在“难以理解”的东西上,这些东西在现实世界的程序中很少使用。

我仍然有问题的“让”命令(我从来没有发现一个用途)和SelectMany(我已经使用过,但我不确定我是否做对了)

在LINQ to SQL中,我经常看到人们不理解DataContext,它可以如何使用以及应该如何使用。太多的人看不到DataContext是什么,它是一个工作单元对象,而不是一个持久化对象。

我见过很多次,人们试图单例化一个DataContext/ session it/ etc,而不是为每个操作创建一个新的时间。

然后是在IQueryable被评估之前处理DataContext但那更多的是人们不理解IQueryable而不是DataContext。

另一个我经常混淆的概念是查询语法和表达式语法。在这一点上,我将使用最简单的方法,通常坚持使用表达式语法。很多人仍然没有意识到他们最终会生成相同的东西,查询终究被编译成表达式。

理解Linq提供者之间的抽象何时泄漏。有些东西适用于对象,但不适用于SQL(例如,. takewhile)。一些方法可以被翻译成SQL (ToUpper),而另一些则不能。有些技术在对象中更有效,而其他技术在SQL中更有效(不同的连接方法)。

我很想知道我是否需要知道表达式树是什么,以及为什么。

我对LINQ还是个新手。以下是我第一次尝试时遇到的问题

  • 将多个查询合并为一个查询
  • 在Visual Studio中有效地调试LINQ查询。

好了,由于需要,我写了一些表达式的东西。我不是100%的满意博客和LiveWriter合谋的格式,但它现在做…

不管怎样,接下来……我希望得到任何反馈,特别是如果人们在某些方面需要更多信息的话。

在这里,喜欢还是讨厌它…

有几件事。

  1. 人们认为Linq就是Linq to SQL。
  2. 有些人认为他们可以开始用Linq查询替换所有的foreach/逻辑,而不考虑性能影响。

哪个更快,内联Linq-to-Sql还是使用Tsql spprocs的Linq-to-Sql

... 是否有使用服务器端(Sproc)或客户端(内联Linq)查询更好的情况。

执行查询时var代表什么?

它是iQueryableiSingleResultiMultipleResult,还是根据实现而改变。在c#中使用(似乎是)动态类型与标准静态类型之间存在一些猜测。

理解语法“魔法”。理解语法如何转换为方法调用,选择了哪些方法调用。

例如:

from a in b
from c in d
where a > c
select new { a, c }

转换为方法调用。

group by仍然让我头晕。

任何关于延迟执行的困惑都应该能够通过逐步执行一些简单的基于linq的代码并在观察窗口中进行操作来解决。

对于LINQ2SQL:熟悉一些生成的SQL并编写可以转换为良好(快速)SQL的LINQ查询。这是知道如何平衡LINQ查询的声明性和它们需要在已知环境(SQL Server)中快速执行的真实性这一更大问题的一部分。

你可以得到一个完全不同的SQL生成查询通过改变一个很小很小的东西在LINQ代码。如果您正在基于条件语句创建表达式树(即添加可选的过滤条件),这可能特别危险。

我最初没有意识到的是LINQ语法需要IEnumerable<T>IQueryable<T>才能工作,LINQ只是关于模式匹配。

alt text http://bartdesmet.info/images_wlw/QIsIQueryabletheRightChoiceforMe_13478/image_thumb_3.png

这就是答案(不,我没有写了那个博客,Bart De Smet做了,他是我发现的LINQ上最好的博主之一)。

我发现查询表达式语法只支持LINQ功能的一个子集,这有点令人失望,因此您无法避免时不时地链接扩展方法。例如,Distinct方法不能使用查询表达式语法调用。要使用Distinct方法,需要调用扩展方法。另一方面,查询表达式语法在许多情况下非常方便,所以您也不想跳过它。

关于LINQ的演讲可以包括一些实用的指导方针,比如什么时候更喜欢一种语法而不是另一种,以及如何混合使用它们。

如前所述,延迟加载和延迟执行

LINQ to object和LINQ to XML (IEnumerable)与LINQ to SQL(IQueryable)有何不同

如何构建一个数据访问层,业务层和表示层与LINQ在所有层....这是个很好的例子。

我不知道这是否属于误解,但对我来说,就是未知。

我很高兴了解了DataLoadOptions以及在进行特定查询时如何控制连接哪些表。

更多信息请参见这里:MSDN: DataLoadOptions

我认为在LINQ中最重要的一点是如何让自己陷入性能方面的麻烦。例如,使用LINQ的计数作为循环条件是非常非常不明智的。

我想说,LINQ最容易被误解(或者不应该被理解?)的方面是这个IQueryable自定义LINQ提供者

我已经使用LINQ有一段时间了,完全适应IEnumerable世界,并且可以用LINQ解决大多数问题。

但是当我开始看和阅读IQueryable,表达式和自定义linq提供程序时,它让我头晕目眩。如果您想了解一些相当复杂的逻辑,可以看看LINQ to SQL是如何工作的。

我期待了解LINQ的这一方面……

当然,这并不是“最困难的”,只是需要添加到列表中:

ThenBy() extension method

没有看到它的实现,我最初对它是如何工作的感到困惑。每个人都能很好地理解逗号分隔的排序字段在SQL中是如何工作的——但从表面上看,我怀疑ThenBy会做我真正想要它做的事情。它怎么能“知道”之前的排序字段是什么呢——看起来它应该知道。

我现在要去研究一下了……

正如大多数人所说,我认为最被误解的部分是假设LINQ只是T-SQL的替代品。 我的经理认为自己作为一个TSQL专家不会让我们在我们的项目中使用LINQ,甚至讨厌微软发布这样的东西!!< / p >

我认为误解了LINQ的一部分,它是一个语言扩展,而不是一个数据库扩展或构造。

LINQLINQ to SQL大得多。

既然我们大多数人都在集合中使用了LINQ,我们就再也不会回去了!

LINQ是。net自2.0的泛型和3.0的匿名类型以来最重要的特性。

现在我们有了Lambda,我等不及要进行并行编程了!

我知道延迟执行的概念现在应该被灌输给我了,但这个例子确实帮助我实际掌握了它:

static void Linq_Deferred_Execution_Demo()
{
List<String> items = new List<string> { "Bob", "Alice", "Trent" };


var results = from s in items select s;


Console.WriteLine("Before add:");
foreach (var result in results)
{
Console.WriteLine(result);
}


items.Add("Mallory");


//
//  Enumerating the results again will return the new item, even
//  though we did not re-assign the Linq expression to it!
//


Console.WriteLine("\nAfter add:");
foreach (var result in results)
{
Console.WriteLine(result);
}
}

上面的代码返回如下:

Before add:
Bob
Alice
Trent


After add:
Bob
Alice
Trent
Mallory

大O符号。LINQ使得编写O(n^4)算法变得非常容易,如果你不知道自己在做什么的话。

一些错误消息,特别是从LINQ到SQL的错误消息可能非常令人困惑。露齿而笑

和其他人一样,我也被推迟执行的问题困扰过几次。我认为对我来说最困惑的事情是SQL Server查询提供程序,以及你能用它做什么和不能做什么。

我仍然惊讶于你不能在有时为空的小数/货币列上执行Sum()。使用DefaultIfEmpty()是行不通的。:(

我打赌几乎有人知道:你可以在linq查询中使用内联if。就像这样:

var result = from foo in bars where (
((foo.baz != null) ? foo.baz : false) &&
foo.blah == "this")
select foo;

我猜你也可以插入,尽管我还没试过。

编译查询

事实上,你不能链接IQueryable,因为它们是方法调用(而仍然不是别的,而是可翻译的SQL !),而且几乎不可能绕过它,这是令人难以置信的,并且严重违反了DRY。我需要我的IQueryable的ad-hoc中,我没有编译查询(我只有编译查询繁重的场景),但在编译查询中,我不能使用它们,而是需要再次编写常规查询语法。现在我在2个地方做相同的子查询,需要记住如果有变化就更新,等等。一场噩梦。

花了我道路太长时间才意识到许多LINQ扩展方法,如Single()SingleOrDefault()等都有重载,使用lambdas。

你可以:

Single(x => x.id == id)

我不需要这么说——一些糟糕的教程让我养成了这样做的习惯

Where(x => x.id == id).Single()

我不认为每个人都能理解嵌套循环有多容易。

例如:

from outerloopitem in outerloopitems
from innerloopitem in outerloopitem.childitems
select outerloopitem, innerloopitem

正如大多数人所说,我认为最被误解的部分是假设LINQ只是T-SQL的替代品。我的经理认为自己是一个TSQL专家,他不让我们在项目中使用LINQ,甚至讨厌微软发布这样的东西!!

事实上,你不能链IQueryable,因为它们是方法调用(但仍然没有其他可翻译的SQL !),而且几乎不可能绕过它,这是令人难以置信的,并造成了对DRY的巨大违反。我需要我的IQueryable在ad-hoc中,我没有编译查询(我只有编译查询的重型场景),但在编译查询中,我不能使用它们,而是需要再次编写常规查询语法。现在我在2个地方做相同的子查询,需要记住如果有变化就更新,等等。一场噩梦。

IQueryable接受Expression<Func<T1, T2, T3, ...>>Func<T1, T2, T3, ...>这两种情况,没有给出关于第二种情况下性能下降的提示。

下面是代码示例,演示了我的意思:

[TestMethod]
public void QueryComplexityTest()
{
var users = _dataContext.Users;


Func<User, bool>                funcSelector =       q => q.UserName.StartsWith("Test");
Expression<Func<User, bool>>    expressionSelector = q => q.UserName.StartsWith("Test");


// Returns IEnumerable, and do filtering of data on client-side
IQueryable<User> func = users.Where(funcSelector).AsQueryable();
// Returns IQuerible and do filtering of data on server side
// SELECT ... FROM [dbo].[User] AS [t0] WHERE [t0].[user_name] LIKE @p0
IQueryable<User> exp = users.Where(expressionSelector);
}

事务(不使用TransactionScope)

我认为关于LINQ to SQL的第一个误解是,你仍然必须了解SQL才能有效地使用它。

关于Linq to Sql的另一个误解是,为了让它工作,你仍然必须降低数据库的安全性到荒谬的地步。

第三点是将Linq to Sql与动态类一起使用(意味着类定义是在运行时创建的)会导致大量的即时编译。这绝对会破坏性能。

如何LINQ到SQL翻译它!

假设我们有一个有3个字段的表;A, B &C(整数,表名为“Table1”).
. C
. C(整数,表名为“Table1”) 我是这样显示的:
[A, B, C]

. 现在我们想要得到这样的结果:
[X = A, Y = B + C]

.

我们有这样一门课:

public class Temp
{
public Temp(int x, int y)
{
this.X = x;
this.Y = y;
}


public int X { get; private set; }
public int Y { get; private set; }
}

然后我们这样使用它:

using (MyDataContext db = new MyDataContext())
{
var result = db.Table1.Select(row =>
new Temp(row.A, row.B + row.C)).ToList();
}

生成的SQL查询是:

SELECT [t0].[A] AS [x], [t0].[B] + [t0].[C] AS [y]
FROM [Table1] AS [t0]

它转换了Temp的.ctor,它知道我想要“row”。B + row.C”(甚至更多…)放在我的类构造函数的“y”参数上!

我对这些译文很感兴趣。我喜欢这样,我认为编写这样的翻译器(LINQ to Something)有点难!

当然!这是一个坏消息:LINQ to Entities(4.0)不支持带参数的构造函数。(为什么不呢?)

我发现“创建一个表达式树”很难。有很多事情困扰我,你可以用LINQ, LINQ到SQL和ADO。净。

解释为什么Linq不像sql语法中那样简单地处理左外连接。 参见这篇文章:用LINQ实现左连接如何:执行左外连接(c#编程指南) 当我遇到这个障碍时,我非常失望,我对语言的所有尊重都消失了,我以为它只是一种很快就会消失的东西。严肃的人不会愿意使用缺少这些经过实战验证的原语的语法。你能否解释一下为什么不支持这种设置操作。我将成为一个更好更开放的人。

我发现很难找到关于匿名类型的明确信息,特别是关于web应用程序中的性能。 我还会在查询和性能相关的主题中建议更好和实用的Lamda表达式示例和“如何”部分

希望我的简短清单能有所帮助!