Interesting LINQ side affect, Pass in empty List<int> using Contains and Get Where 0 == 1. Hmm
Sunday 14 June 2009 @ 8:21 am

 

We’ve built a data access layer on top of LINQ2SQL for dynamically building the layer we call for data access.  It’s convenient because we pass in a query object as a parameter that has a bunch of nullable variables in it.  Here is kind of what it looks like:

    public partial class CodeGenTestQuery : QueryBase
    {
        public int? Id { get; set; }
        public List<int> Ids { get; set; }
        public bool? IsStarred { get; set; }
        ...

If I pass an empty list of int’s into Ids, I have a line of code that build the query as follows:

if (query.Ids != null) baseQuery = baseQuery.Where(a => query.Ids.Contains(a.Id));

This works fine as long as a pass into ids either null, or a list that contains more than one object. However, if I pass in an empty list like this:

new CodeGenTestQuery
    {
         Ids = new List<int>() { }, MyAge = 2
     }

Then, the result of the LINQ query is it creates a where clause that says something like this:

SELECT [t0].[Id],
       [t0].[IsStarred]
FROM [dbo].[CodeGenTest] AS [t0]
WHERE ([t0].[MyAge] = 2) AND
      (0 = 1)

Which means you will not get the MyAge == 2 record ever

So, I changed my c# as follows and now I get what I expect.

if (query.Ids != null)
            {
                if (query.Ids.Count > 0)
                {
                    baseQuery = baseQuery.Where(a => query.Ids.Contains(a.Id));
                }
}

I can see this kind of thinking on the LINQ2SQL team, but it’s a little insidious if you ask me.

Comments (4) - Posted in C#, LINQ, LINQ to SQL  




4 Responses to “Interesting LINQ side affect, Pass in empty List<int> using Contains and Get Where 0 == 1. Hmm”

  1. gunteman Says:

    I think Linq2Sql handles it correctly. The only other way of handling it would be to not execute the query at all, since it will never return anything, but I don’t think we can expect that since

    1. The absence of a query execution could indicate a problem
    2. The query may be a subquery
    3. It’s not up to the Linq2Sql provider to perform any query logic

    SQL Server will see that the query can’t return any results, so there will be exactly zero I/O cost.

  2. peter kellner Says:

    yes, I agree LINQ handles it correctly. It just tricked me some so I thought i’d post it in case someone else runs into the same issue. It’s certainly not obvious.

  3. Damien Guard Says:

    Whenever you see 1=0 in the TSQL LINQ to SQL generates it means it believes you are testing something that can’t be nullable with something that must be nullable…

    [)amien

  4. gunteman Says:

    @peter: OK!

    @Damien: I’m not sure I follow..

Leave a Reply