Description
When using EF.Functions.Like on a property mapped via a ValueConverter from any strongly-typed type to string (both struct and class), Entity Framework Core emits a redundant CAST(... AS string) (or ::text in PostgreSQL) in the generated SQL.
Your code:
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Microsoft.Extensions.Logging;
namespace EfInvalidSql;
public class Program
{
public static async Task Main(params string[] args)
{
MyContext context = new();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var users = await context.Set<User>()
.Where(x => EF.Functions.Like(x.Name, "Name%"))
.ToListAsync();
}
}
public class User
{
public required int Id { get; set; }
public required FullName Name { get; set; }
}
public readonly record struct FullName
{
public FullName(string value)
{
Value = value;
}
public string Value { get; }
public static implicit operator string(FullName fullName)
{
return fullName.Value;
}
}
public class FullNameConverter : ValueConverter<FullName, string>
{
public FullNameConverter() : base(
v => v.Value,
v => new FullName(v))
{
}
}
public class MyContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer("Server=localhost,7438;Database=TestDb;User Id=sa;Password=RMfL3Tx%bZ5b;TrustServerCertificate=True;")
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
}
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder.Properties<FullName>()
.HaveConversion<FullNameConverter>()
.HaveColumnType("text");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>(builder =>
{
builder.ToTable("Users");
});
modelBuilder.Entity<User>()
.HasData(
new User { Id = 1, Name = new FullName("Name1") },
new User { Id = 2, Name = new FullName("Name2") }
);
}
}
Generated SQL by MSSQL provider:
SELECT [u].[Id], [u].[Name]
FROM [Users] AS [u]
WHERE CAST([u].[Name] AS nvarchar(max)) LIKE N'Name%'
Generated SQL by Npgsql provider:
SELECT u."Id", u."Name"
FROM "Users" AS u
WHERE u."Name"::text LIKE 'Name%'
EF Core version
9.0.6
Database provider
MSSQL provider and Npgsql Entity Framework Core provider for PostgreSQL
Target framework
.NET 9.0
Operating system
Windows 11
IDE
Visual Studio 17.4.5
Description
When using EF.Functions.Like on a property mapped via a ValueConverter from any strongly-typed type to string (both struct and class), Entity Framework Core emits a redundant CAST(... AS string) (or ::text in PostgreSQL) in the generated SQL.
Your code:
Generated SQL by MSSQL provider:
Generated SQL by Npgsql provider:
EF Core version
9.0.6
Database provider
MSSQL provider and Npgsql Entity Framework Core provider for PostgreSQL
Target framework
.NET 9.0
Operating system
Windows 11
IDE
Visual Studio 17.4.5