question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

EFCore 5.0 - UseRelationalNulls value is not being honored

See original GitHub issue

I am running a sample application using SqlServer provider for EFCore 5. I am noticing that setting UseRelationalNulls to true or false is not having any impact on the generated query. Here is how I am using UseRelationalNulls.

optionsBuilder.UseSqlServer(@"<connection_string>" , v => { v.UseRelationalNulls(false); });

Here is the linq I am trying to execute.

string col2 = null;
var query = db.Set<TAB1>().Where(v => v.COL2 == col2).ToList();

Here is the query generated irrespective of UseRelationalNulls being set to TRUE of FALSE.

SELECT [t].[COL1], [t].[COL2]
FROM [TAB1] AS [t]
WHERE [t].[COL2] IS NULL

I was hoping if UseRelationalNulls is set to false, the generated query should be in following format.

SELECT [t].[COL1], [t].[COL2]
FROM [TAB1] AS [t]
WHERE [t].[COL2] = :<parameter>

Is my understanding of UseRelationalNulls correct? If yes, Is this a bug or am I missing something? Please could you clarify?

Here is the sample application to reproduce the issue.

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

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

                var data1 = new TAB1 { COL2 = "shivam" };
                var data2 = new TAB1 { COL2 = null };

                db.Add(data1);
                db.Add(data2);
                db.SaveChanges();

                string col2 = null;
                var query = db.Set<TAB1>().Where(v => v.COL2 == col2).ToList();
            }
        }
    }
    class MyContext : DbContext
    {
        public DbSet<TAB1> TAB1 { get; set; }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(@"<connection_string>" , v => { v.UseRelationalNulls(false); })
                .UseLoggerFactory(_myLoggerFactory);
        }
        public static readonly LoggerFactory _myLoggerFactory = new LoggerFactory(new[] { new Microsoft.Extensions.Logging.Debug.DebugLoggerProvider() });
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<TAB1>(e =>
            {
                e.HasKey(p => p.COL1);
            });
        }
    }
    public class TAB1
    {
        public int COL1 { get; set; }
        public string COL2 { get; set; }
    }
}

EF Core version: 5.0.10 Database provider: Microsoft.EntityFrameworkCore.SqlServer Target framework: .NET 5.0 Operating system: Windows 10 IDE: Visual Studio 2019 16.3

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

3reactions
maumarcommented, Sep 22, 2021

The “spirit” behind useRelationalNulls flag is to allow for simplified sql in cases where our c# comparison semantics causes perf issues (to many null checks, unable to use index etc.) We apply it to comparisons which can produce those extra null check terms.

In case when we compare with a null constant or a null parameter (at that point we know it’s value is null), we don’t need to add extra terms that would impact perf and so we always convert the call to ISNULL.

Moreover, x = NULL always returns null, so we think it’s unlikely that this would actually be the intention of the user, as opposed to x IS NULL.

@shvmgpt116 do you actually have a scenario where x = NULL translation is desirable, or you are looking at it from the perspective of consistency/correctness? (I do agree that the behavior is not consistent)

2reactions
maumarcommented, Sep 30, 2021

@andrewharry Unfortunately, we decided to keep the behavior as is. We believe IS NULL is a better translation when user intention is taken into account.

As to a potential solution, you can try using DbCommandInterceptor (see docs: https://docs.microsoft.com/en-us/ef/core/logging-events-diagnostics/interceptors). It can intercept DbCommand before it’s being executed and convert all instances of IS NULL into = NULL and IS NOT NULL into <> NULL

If the entire codebase uses relational nulls, EF will not inject those null checks, apart from the transformation that you are trying to get rid of. I looked into the code and (unless I missed something) the only other places when EF would create IS NULL calls are:

  • translation of Nullable<T>.HasValue,
  • Contains on a list which itself contains a null, e.g. new { "Foo", "Bar", null }.Contains(c.Name),
  • some advanced mapping constructs, e.g. TPT, shared type entities (in optional dependent conditions).

If your codebase doesn’t use these I think it’s worth a shot.

Read more comments on GitHub >

github_iconTop Results From Across the Web

RelationalDbContextOptionsBuil...
Configures the context to use relational database semantics when comparing null values. By default, Entity Framework will use C# semantics for null values,...
Read more >
UseRelationalNulls does not work with SELECT conditions
I observed a behavioural inconsistency of UseRelationalNulls method when used with Linq WHERE and SELECT conditions.
Read more >
Breaking changes in EF Core 5.0
Complete list of breaking changes introduced in Entity Framework Core 5.0.
Read more >
Entity Framework Core Cookbook - Second Edition
Implementing the unit of work pattern. Getting ready. How to do it… How it works… There's more… Call per change. Interface Segregation Principle....
Read more >
Update is not working in OwnsMany Value Object ...
First off, they are not considered part of the entity data. ... All this is because EF Core has no information about the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found