Note that there are some explanatory texts on larger screens.

plurals
  1. POLINQ to SQL bug (or very strange feature) when using IQueryable, foreach, and multiple Where
    primarykey
    data
    text
    <p>I ran into a scenario where LINQ to SQL acts very strangely. I would like to know if I'm doing something wrong. But I think there is a real possibility that it's a bug.</p> <p>The code pasted below isn't my real code. It is a simplified version I created for this post, using the Northwind database.</p> <p>A little background: I have a method that takes an <code>IQueryable</code> of <code>Product</code> and a "filter object" (which I will describe in a minute). It should run some "Where" extension methods on the <code>IQueryable</code>, based on the "filter object", and then return the <code>IQueryable</code>.</p> <p>The so-called "filter object" is a <code>System.Collections.Generic.List</code> of an anonymous type of this structure: <code>{ column = fieldEnum, id = int }</code></p> <p>The fieldEnum is an enum of the different columns of the <code>Products</code> table that I would possibly like to use for the filtering.</p> <p>Instead of explaining further how my code works, it's easier if you just take a look at it. It's simple to follow.</p> <pre><code>enum filterType { supplier = 1, category } public IQueryable&lt;Product&gt; getIQueryableProducts() { NorthwindDataClassesDataContext db = new NorthwindDataClassesDataContext(); IQueryable&lt;Product&gt; query = db.Products.AsQueryable(); //this section is just for the example. It creates a Generic List of an Anonymous Type //with two objects. In real life I get the same kind of collection, but it isn't hard coded like here var filter1 = new { column = filterType.supplier, id = 7 }; var filter2 = new { column = filterType.category, id = 3 }; var filterList = (new[] { filter1 }).ToList(); filterList.Add(filter2); foreach(var oFilter in filterList) { switch (oFilter.column) { case filterType.supplier: query = query.Where(p =&gt; p.SupplierID == oFilter.id); break; case filterType.category: query = query.Where(p =&gt; p.CategoryID == oFilter.id); break; default: break; } } return query; } </code></pre> <p>So here is an example. Let's say the List contains two items of this anonymous type, <code>{ column = fieldEnum.Supplier, id = 7 }</code> and <code>{ column = fieldEnum.Category, id = 3}</code>.</p> <p>After running the code above, the underlying SQL query of the <code>IQueryable</code> object should contain:</p> <pre><code>WHERE SupplierID = 7 AND CategoryID = 3 </code></pre> <p>But in reality, after the code runs the SQL that gets executed is</p> <pre><code>WHERE SupplierID = 3 AND CategoryID = 3 </code></pre> <p>I tried defining <code>query</code> as a property and setting a breakpoint on the setter, thinking I could catch what's changing it when it shouldn't be. But everything was supposedly fine. So instead I just checked the underlying SQL after every command. I realized that the first <code>Where</code> runs fine, and <code>query</code> stays fine (meaning <code>SupplierID = 7</code>) until right after the <code>foreach</code> loop runs the second time. Right after <code>oFilter</code> becomes the second anonymous type item, and not the first, the 'query' SQL changes to <code>Supplier = 3</code>. So what must be happening here under-the-hood is that instead of just remembering that <code>Supplier</code> should equal 7, LINQ to SQL remembers that Supplier should equal <code>oFilter.id</code>. But <code>oFilter</code> is a name of a single item of a <code>foreach</code> loop, and it means something different after it iterates.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload