The result of the translation of Nullable<bool>.ToString() is different depending on whether the method is invoked on a column or another type of expression.
When invoked on a null in a column, the result is null, while doing the same on an expression returns the string "True" (even though the value is null).
An example program that showcases the bug is:
using System;
using System.Data;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using var db = new BloggingContext();
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
var bools = db.Blogs
.Select(x => x.NullableBool)
.Select(x => new { Raw = x, String = x.ToString() })
.ToList();
foreach (var x in bools) {
Console.WriteLine($"'{x.Raw.ToString() ?? "-"}' -> '{x.String ?? "-"}'");
}
bools = db.Blogs
.Select(x => x.NullableBool & (x.BlogId > 0))
.Select(x => new { Raw = x, String = x.ToString() })
.ToList();
foreach (var x in bools) {
Console.WriteLine($"'{x.Raw.ToString() ?? "-"}' -> '{x.String ?? "-"}'");
}
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options
.LogTo(Console.WriteLine, Microsoft.Extensions.Logging.LogLevel.Information)
.UseSqlite($"Data Source=test.db");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>().HasData(new Blog { BlogId = 1, NullableBool = false });
modelBuilder.Entity<Blog>().HasData(new Blog { BlogId = 2, NullableBool = true });
modelBuilder.Entity<Blog>().HasData(new Blog { BlogId = 3, NullableBool = null });
}
}
public class Blog
{
public int BlogId { get; set; }
public bool? NullableBool { get; set; }
}
The first query is translated to
SELECT "b"."NullableBool" AS "Raw", CASE
WHEN "b"."NullableBool" = 0 THEN 'False'
WHEN "b"."NullableBool" = 1 THEN 'True'
ELSE NULL
END AS "String"
FROM "Blogs" AS "b"
hence the command writes
'False' -> 'False'
'True' -> 'True'
'' -> '-'
(notation: value converted to string in C# -> value converted to string by EFCore; '-' is used as a marker for null)
The second query is translated to
SELECT "b"."NullableBool" & ("b"."BlogId" > 0) AS "Raw", CASE
WHEN "b"."NullableBool" & ("b"."BlogId" > 0) = 0 THEN 'False'
ELSE 'True'
END AS "String"
FROM "Blogs" AS "b"
hence the program writes
'False' -> 'False'
'True' -> 'True'
'' -> 'True'
Include provider and version information
EF Core version: 8.0.6
Database provider: Microsoft.EntityFrameworkCore.Sqlite
Target framework: .NET 8.0
Operating system: Linux (/WSL)
IDE: Visual Studio Code 1.89.1
The result of the translation of
Nullable<bool>.ToString()is different depending on whether the method is invoked on a column or another type of expression.When invoked on a
nullin a column, the result isnull, while doing the same on an expression returns the string"True"(even though the value isnull).An example program that showcases the bug is:
The first query is translated to
hence the command writes
(notation: value converted to string in C# -> value converted to string by EFCore; '-' is used as a marker for
null)The second query is translated to
hence the program writes
Include provider and version information
EF Core version: 8.0.6
Database provider: Microsoft.EntityFrameworkCore.Sqlite
Target framework: .NET 8.0
Operating system: Linux (/WSL)
IDE: Visual Studio Code 1.89.1