Skip to content

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

Updated: at 11:17 PM

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.