我可以或应该在LINQ查询中连接两个Where子句
本文关键字:两个 子句 Where 连接 查询 LINQ 我可以 | 更新日期: 2023-09-27 18:19:06
我有以下类:
public partial class Content
{
public int ContentId { get; set; }
public int ContentTypeId { get; set; }
public string Title { get; set; }
public string Text { get; set; }
public int SubjectId { get; set; }
public virtual Subject Subject { get; set; }
}
我明白我可以像这样使用Linq查询:
.Where(a => a.SubjectId == subjectId)
但是我怎样才能使它有另一个条件
.Where(a => a.ContentTypeId == contentTypId)
是否有一种方法可以将它们合并为一个,或者它们应该保持两个?
仅使用一个包含所有条件的Where
子句:
.Where(a => a.SubjectId == subjectId && a.ContentTypeId == contentTypId)
或两个Where
子句,各处理一个条件:
.Where(a => a.SubjectId == subjectId)
.Where(a => a.ContentTypeId == contentTypId)
是等价的,因为LINQ查询的执行被延迟到调用结果。
您还可以:
.Where(a => a.SubjectId == subjectId).Where(a => a.ContentTypeId == contentTypId)
omer schleifer的回答让我对这种情况进行基准测试,并最终检查创建的IL,看看是否在链接子句中有性能影响。
让我们看看下面的例子:
var numbers = new List<int>() { 1, 2 ,3,4,5,6,7,8,9,10};
IEnumerable<int> query = numbers.Where(x=> x>2 && x<5);
将导致以下IL:
IL_0001: newobj System.Collections.Generic.List<System.Int32>..ctor
IL_0006: stloc.2 // <>g__initLocal0
IL_0007: ldloc.2 // <>g__initLocal0
...
...
...
IL_0059: ldloc.2 // <>g__initLocal0
IL_005A: stloc.0 // numbers
IL_005B: ldloc.0 // numbers
IL_005C: ldsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate2
IL_0061: brtrue.s IL_0076
IL_0063: ldnull
IL_0064: ldftn b__1
IL_006A: newobj System.Func<System.Int32,System.Boolean>..ctor
IL_006F: stsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate2
IL_0074: br.s IL_0076
IL_0076: ldsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate2
IL_007B: call System.Linq.Enumerable.Where
IL_0080: stloc.1 // query
IL_0081: ldloc.1 // query
b__1:
IL_0000: ldarg.0
IL_0001: ldc.i4.2
IL_0002: ble.s IL_000A
IL_0004: ldarg.0
IL_0005: ldc.i4.5
IL_0006: clt
IL_0008: br.s IL_000B
IL_000A: ldc.i4.0
IL_000B: stloc.0 // CS$1$0000
IL_000C: br.s IL_000E
IL_000E: ldloc.0 // CS$1$0000
IL_000F: ret
//链接示例:
var numbers = new List<int>() { 1, 2 ,3,4,5,6,7,8,9,10};
IEnumerable<int> query = numbers.Where(x=> x>2).Where(x => x<5);
//结果如下:
IL_0001: newobj System.Collections.Generic.List<System.Int32>..ctor
IL_0006: stloc.2 // <>g__initLocal0
IL_0007: ldloc.2 // <>g__initLocal0
IL_0008: ldc.i4.1
...
...
...
IL_0058: nop
IL_0059: ldloc.2 // <>g__initLocal0
IL_005A: stloc.0 // numbers
IL_005B: ldloc.0 // numbers
IL_005C: ldsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate3
IL_0061: brtrue.s IL_0076
IL_0063: ldnull
IL_0064: ldftn b__1
IL_006A: newobj System.Func<System.Int32,System.Boolean>..ctor
IL_006F: stsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate3
IL_0074: br.s IL_0076
IL_0076: ldsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate3
IL_007B: call System.Linq.Enumerable.Where <--------first where call
IL_0080: ldsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate4
IL_0085: brtrue.s IL_009A
IL_0087: ldnull
IL_0088: ldftn b__2
IL_008E: newobj System.Func<System.Int32,System.Boolean>..ctor
IL_0093: stsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate4
IL_0098: br.s IL_009A
IL_009A: ldsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate4
IL_009F: call System.Linq.Enumerable.Where <--------second where call
IL_00A4: stloc.1 // query
IL_00A5: ldloc.1 // query
b__1:
IL_0000: ldarg.0
IL_0001: ldc.i4.2
IL_0002: cgt
IL_0004: stloc.0 // CS$1$0000
IL_0005: br.s IL_0007
IL_0007: ldloc.0 // CS$1$0000
IL_0008: ret
b__2:
IL_0000: ldarg.0
IL_0001: ldc.i4.5
IL_0002: clt
IL_0004: stloc.0 // CS$1$0000
IL_0005: br.s IL_0007
IL_0007: ldloc.0 // CS$1$0000
IL_0008: ret
该示例显示有两个调用,第二个调用接收第一个结果作为输入。
所以在Linq to Objects
中会有一个性能打击。性能恶化的程度将取决于数据量和where子句的顺序,第一个子句过滤的越多,下一个子句必须操作的就越少,等等……在我看来,在大多数情况下,性能影响不会很大。
在Linq to SQL
链Where子句将不会影响性能,因为将创建相同的SQL