Alan2
Alan2

Reputation: 24572

Can or should I join two Where clauses together in a LINQ Query?

I have the following class:

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; }
}

I understand I can use a Linq query like this:

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

However how can I make it so there is another condition

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

is there a way I can join these into one where or should they remain as two?

Upvotes: 1

Views: 313

Answers (3)

xlecoustillier
xlecoustillier

Reputation: 16351

Using only one Where clause containing every condition:

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

Or two Where clauses, dealing with one condition each:

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

is equivalent, as the LINQ query execution is deferred until the call to the result.

Upvotes: 6

makc
makc

Reputation: 2579

omer schleifer answer got me to bench mark the case and eventually to check the created IL to see if there is a performance hit in chaining clause or not..

lets look at the following example:

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);

results in the following 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  

//the chaining example:

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);

//result in the following 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

The example Shows that there are to where calls and the second one receives the first one results as an input.
So in Linq to Objects there will be a performance hit.
the magnitude of the performance deterioration will depend on the amount of data and the order of the where clauses the more the first clause will filter the less the next one will have to operate on and so on... In my opinion in most cases the performance hit wont be significant.

In Linq to SQL Chaining Where clause will have no affect on performance because the same SQL will be created.

Upvotes: 1

omer schleifer
omer schleifer

Reputation: 3935

You can also do:

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

this is useful for building queries dynamically in the code.

Upvotes: 3

Related Questions