可以或者我应该在LINQ查询中将两个Where子句连接在一起吗?

时间:2013-06-20 09:26:51

标签: c# linq

我有以下课程:

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) 

有没有一种方法可以将这些加入到哪一个或者它们应该保持为两个?

3 个答案:

答案 0 :(得分:6)

仅使用一个包含所有条件的Where子句:

.Where(a => a.SubjectId == subjectId && a.ContentTypeId == contentTypId)

或两个Where条款,分别处理一个条件:

.Where(a => a.SubjectId == subjectId)
.Where(a => a.ContentTypeId == contentTypId)

是等效的,因为LINQ查询执行被推迟到调用结果。

答案 1 :(得分:3)

你也可以这样做:

.Where(a => a.SubjectId == subjectId).Where(a => a.ContentTypeId == contentTypId) 

这对于在代码中动态构建查询非常有用。

答案 2 :(得分:1)

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:

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。