Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Logical NOT before contains does not include NULL check #14171

Closed
S1r-Lanzelot opened this issue Dec 14, 2018 · 6 comments
Closed

Logical NOT before contains does not include NULL check #14171

S1r-Lanzelot opened this issue Dec 14, 2018 · 6 comments

Comments

@S1r-Lanzelot
Copy link

I have a piece of code that looks like the following:

public List<string> ResolveDomicileIdsByForeignGeoId(IEnumerable<int?> geoIds)
        {
            var domIds = myContext.DomicileMappings
                .Where(x => !geoIds.Contains(x.GeoId))
                .Select(x => x.DomicileId).Distinct().ToList();
            return domIds;
        }

The GeoId column in the DomicileMappings table is nullable.

The generated sql for this query is as follows:

SELECT DISTINCT [x].[DomicileId]
FROM [DomicileMappings] AS [x]
WHERE [x].[GeoId] NOT IN (77)

However I would expect it to check for nulls as well, as follows:

SELECT DISTINCT [x].[DomicileId]
FROM [DomicileMappings] AS [x]
WHERE [x].[GeoId] NOT IN (77) OR [x].[GeoId] IS NULL

since the column is nullable. Am I wrong to expect this?

Further technical details

EF Core version: v2.2.0
Database Provider: Sql Server (Azure)

@S1r-Lanzelot S1r-Lanzelot changed the title Logical NOT before contains not include NULL Logical NOT before contains does not include NULL check Dec 14, 2018
@S1r-Lanzelot
Copy link
Author

S1r-Lanzelot commented Dec 14, 2018

Furthermore, I would expect this functionality in Linq To Sql as it exists with in memory objects:

List<int?> DomicileMappings = new List<int?>();
List<int?> geoIds = new List<int?>();

geoIds.Add(1);
DomicileMappings.Add(1);
DomicileMappings.Add(2);
DomicileMappings.Add(null);

var domIds = DomicileMappings.Where(x => !geoIds.Contains(x)).ToList();
//domIds  = 2, null

@ajcvickers ajcvickers added this to the 3.0.0 milestone Dec 17, 2018
@smitpatel smitpatel removed this from the 3.0.0 milestone Dec 17, 2018
@smitpatel
Copy link
Member

This issue is lacking enough information for us to effectively reproduce. Please post a runnable project/solution or complete code listing that demonstrates the behavior you are seeing.

@smitpatel
Copy link
Member

Following code

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace EFSampleApp
{
    public class Program
    {
        public static void Main(string[] args)
        {
            using (var db = new MyContext())
            {
                // Recreate database
                db.Database.EnsureDeleted();
                db.Database.EnsureCreated();

                // Seed database

                db.AddRange(
                    new Blog { Value = null },
                    new Blog { Value = 2 }
                    );

                db.SaveChanges();
            }

            using (var db = new MyContext())
            {
                // Run queries
                var ids = new List<int?>
                {
                    1,
                    2,
                    null
                };
                var query = db.Blogs
                    .Where(b => !ids.Contains(b.Value))
                    .ToList();
                Console.WriteLine(query.Count);
            }

            Console.WriteLine("Program finished.");
        }
    }


    public class MyContext : DbContext
    {
        private static ILoggerFactory LoggerFactory => new LoggerFactory().AddConsole(LogLevel.Trace);

        // Declare DBSets
        public DbSet<Blog> Blogs { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            // Select 1 provider
            optionsBuilder
                .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=_ModelApp;Trusted_Connection=True;Connect Timeout=5;ConnectRetryCount=0")
                //.UseSqlite("filename=_modelApp.db")
                //.UseInMemoryDatabase(databaseName: "_modelApp")
                .EnableSensitiveDataLogging()
                .UseLoggerFactory(LoggerFactory);
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // Configure model
        }
    }

    public class Blog
    {
        public int Id { get; set; }
        public int? Value { get; set; }
    }
}

Generated SQL

      SELECT [b].[Id], [b].[Value]
      FROM [Blogs] AS [b]
      WHERE [b].[Value] NOT IN (1, 2) AND [b].[Value] IS NOT NULL

EF Core version 2.2.0-rtm-35687

@S1r-Lanzelot
Copy link
Author

S1r-Lanzelot commented Dec 17, 2018

@smitpatel thanks for looking at this. I will work on submitting a project to reproduce the issue tonight. Looking at the example code briefly, I wonder if you instantiate the list with just:
var ids = new List<int?> { 1 };

it will replicate the issue... The generated query you posted is different from what I am after.

Regardless, Ill get a reproducable project up soon. Thanks.

@smitpatel
Copy link
Member

@S1r-Lanzelot - That hint was useful. I got repro.
Null semantics are not being applied to InExpression. Assigning @maumar

@maumar
Copy link
Contributor

maumar commented Dec 5, 2019

dupe of #11464

@maumar maumar removed this from the 5.0.0 milestone Dec 5, 2019
@ajcvickers ajcvickers reopened this Oct 16, 2022
@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Oct 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants