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.

remove redundant null semantics terms involving non-null parameters

See original GitHub issue

#15722

Include your code

[Table("Table_1")]
public partial class Table1
{
    [Key]
    public int Id { get; set; }

    public string? Name { get; set; }

    public DateTime CreateTime { get; set; }
}

public partial class TestContext : DbContext
{
    public TestContext()
    {
    }

    public TestContext(DbContextOptions<TestContext> options)
        : base(options)
    {
    }

    public virtual DbSet<Table1> Table1 { get; set; }
}

var services = new ServiceCollection();
services.AddDbContext<TestContext>();
var serviceProvider = services.BuildServiceProvider();

var testContext = serviceProvider.GetRequiredService<TestContext>();
var name = "Varorbc";
var sql = testContext.Table1.Where(a => a.Name != name).ToQueryString()
Console.WriteLine(sql);

Expected Behavior

DECLARE @__name_0 nvarchar(4000) = N'Varorbc';

SELECT [t].[Id], [t].[CreateTime], [t].[Name]
FROM [Table_1] AS [t]
WHERE [t].[Name] <> @__name_0

Actual Behavior

DECLARE @__name_0 nvarchar(4000) = N'Varorbc';

SELECT [t].[Id], [t].[CreateTime], [t].[Name]
FROM [Table_1] AS [t]
WHERE ([t].[Name] <> @__name_0) OR [t].[Name] IS NULL

Include provider and version information

EF Core version:6.0.0-preview.7.21378.4 Database provider: Microsoft.EntityFrameworkCore.SqlServer Target framework: .NET 6.0 Operating system:Win11 IDE: Visual Studio 2022 17.0

Issue Analytics

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

github_iconTop GitHub Comments

1reaction
rojicommented, Sep 3, 2021

I should be based on the behavior in c# rather than the behavior in SQL, right? In fact, I prefer 0 rows of data, because null and [name] are not equal in understanding

This is not how EF Core works - by design. The overwhelming user expectation we see is for their LINQ queries - which are expressed in C# - to bring back the same results from the database is it would if executed in .NET without a database; in fact, our test suite generally makes sure that the same LINQ expression works the same way in SQL and in .NET. This means EF must sometimes “compensate” for differences between C# and SQL via extra clauses. Translation is not a matter of producing a direct, “one-to-one” SQL that looks as close as possible to the C# LINQ query, but rather for the query to produce the same results.

You should probably read our doc page on nullability in queries. Note that you can opt into “relational semantics”, which will make EF behave similar to what you want. However, this is generally discouraged.

Am going to go ahead and close this issue as things are working as designed.

1reaction
rojicommented, Sep 2, 2021

Below is a simple code sample that should help you understand - I’ve taken your code above, and seeded the database with exactly one row containing NULL in the Name column.

Running the SQL which EF generates, I get 1 row as expected:

DECLARE @__name_0 nvarchar(4000) = N'Varorbc';

SELECT COUNT(*)
FROM [Table_1] AS [t]
WHERE ([t].[Name] <> @__name_0) OR [t].[Name] IS NULL;

If I remove the “IS NULL” check, I get 0 rows, which is incorrect (does not match the C# behavior of the LINQ query):

DECLARE @__name_0 nvarchar(4000) = N'Varorbc';

SELECT COUNT(*)
FROM [Table_1] AS [t]
WHERE [t].[Name] <> @__name_0;

Give it a try. The reason is, once again, because [t].[Name] <> N'Varorbc' produces NULL when [Name] is NULL, and the whole expression evaluates to “false” in the context of WHERE.

Code sample
#nullable enable

await using (var ctx = new BlogContext())
{
    await ctx.Database.EnsureDeletedAsync();
    await ctx.Database.EnsureCreatedAsync();

    ctx.Add(new Table1 { Name = null });
    await ctx.SaveChangesAsync();
}

await using (var ctx = new BlogContext())
{
    var name = "Varorbc";
    Console.WriteLine("Count: " + ctx.Table1.Count(a => a.Name != name));
}

public class BlogContext : DbContext
{
    public DbSet<Table1> Table1 { get; set; }

    static ILoggerFactory ContextLoggerFactory
        => LoggerFactory.Create(b => b.AddConsole().AddFilter("", LogLevel.Information));

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
            .UseSqlServer(@"Server=localhost;Database=test;User=SA;Password=Abcd5678;Connect Timeout=60;ConnectRetryCount=0")
            .EnableSensitiveDataLogging()
            .UseLoggerFactory(ContextLoggerFactory);

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
    }
}

[Table("Table_1")]
public class Table1
{
    public int Id { get; set; }
    public string? Name { get; set; }
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

delete duplicates with null values WITHOUT row_number - ...
What I want to do is delete the "duplicates" where Nickname is NULL, while grouping them by the Name-Surname pair but also delete...
Read more >
Use empty string, null or remove empty property in API ...
TLDR; Remove null properties. The first thing to bear in mind is that applications at their edges are not object-oriented (nor functional if ......
Read more >
database design - Why shouldn't we allow NULLs?
The semantic meaning of any specific NULL is left to the application, unlike actual values. ... NULL values represent unknown data NOT unused...
Read more >
The '= NULL' Mistake and other SQL NULL Heresies
You just give it a list of parameters. It evaluates each in turn until it finds one that is not NULL , and...
Read more >
[Proposal] Improve Handling of Nulls in Druid · Issue #4349
Motivation This proposal is to improve handling of null values in druid by treating nulls as missing values which don't actually exist.
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