EFCore 5.0 - UseRelationalNulls value is not being honored
See original GitHub issueI 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:
- Created 2 years ago
- Comments:5 (3 by maintainers)
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)
@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 interceptDbCommand
before it’s being executed and convert all instances ofIS NULL
into= NULL
andIS 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:
Nullable<T>.HasValue
,new { "Foo", "Bar", null }.Contains(c.Name)
,If your codebase doesn’t use these I think it’s worth a shot.