Skip to content

Support value-converted parameters in raw SQL #27354

@roji

Description

@roji

It currently isn't possible to specify a value-converted type as a parameter in raw SQL. It seems like the pre-convention configuration DefaultTypeMapping should make this work:

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    configurationBuilder.DefaultTypeMapping<NameWrapper>()
        .HasConversion(typeof(NameWrapperConverter));
}

... but I still get the exception:

Unhandled exception. System.InvalidOperationException: The current provider doesn't have a store type mapping for properties of type 'NameWrapper'.
   at Microsoft.EntityFrameworkCore.Storage.RelationalTypeMappingSourceExtensions.GetMapping(IRelationalTypeMappingSource typeMappingSource, Type clrType) in /home/roji/projects/efcore/src/EFCore.Relational/Storage/RelationalTypeMappingSourceExtensions.cs:line 89
   at Microsoft.EntityFrameworkCore.Storage.Internal.RawSqlCommandBuilder.Build(String sql, IEnumerable`1 parameters) in /home/roji/projects/efcore/src/EFCore.Relational/Storage/Internal/RawSqlCommandBuilder.cs:line 83
   at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.ExecuteSqlRaw(DatabaseFacade databaseFacade, String sql, IEnumerable`1 parameters) in /home/roji/projects/efcore/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs:line 244
   at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.ExecuteSqlRaw(DatabaseFacade databaseFacade, String sql, Object[] parameters) in /home/roji/projects/efcore/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs:line 159
   at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.ExecuteSqlInterpolated(DatabaseFacade databaseFacade, FormattableString sql) in /home/roji/projects/efcore/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs:line 191
Full repro
await using var ctx = new BlogContext();
await ctx.Database.EnsureDeletedAsync();
await ctx.Database.EnsureCreatedAsync();

ctx.Database.ExecuteSqlInterpolated($@"SELECT * FROM ""Blogs"" WHERE ""Name"" = {new NameWrapper { Name = "foo " }}");

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

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
            .UseSqlServer(@"Server=localhost;Database=test;User=SA;Password=Abcd5678;Connect Timeout=60;ConnectRetryCount=0")
            .LogTo(Console.WriteLine, LogLevel.Information)
            .EnableSensitiveDataLogging();

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    configurationBuilder.DefaultTypeMapping<NameWrapper>()
        .HasConversion(typeof(NameWrapperConverter));
}

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>().Property(b => b.Name)
            .HasConversion(typeof(NameWrapperConverter));
    }

    class NameWrapperConverter : ValueConverter<NameWrapper, string>
    {
        public NameWrapperConverter()
            : base(nw => nw.Name, s => new NameWrapper { Name = s })
        {

        }
    }
}

public class Blog
{
    public int Id { get; set; }
    public NameWrapper Name { get; set; }
}

public class NameWrapper
{
    public string Name { get; set; }
}

Raised by @juchom in npgsql/efcore.pg#2259

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions