DefaultTypeMappings do not seem to be applied in queries.
File a bug
Include your code
Change between SqlServer and Sqlite by modifying the method called in line 6.
Include stack traces
SqlServer:
System.InvalidCastException
HResult=0x80004002
Message=Failed to convert parameter value from a NonGenericWrapper to a Int32.
Source=Microsoft.Data.SqlClient
StackTrace:
at Microsoft.Data.SqlClient.SqlCommand.<>c.<ExecuteDbDataReaderAsync>b__211_0(Task`1 result)
at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke() in /_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/TaskContinuation.cs:line 180
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) in /_/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs:line 179
--- End of stack trace from previous location ---
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) in /_/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs:line 203
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) in /_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs:line 2345
--- End of stack trace from previous location ---
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.<ExecuteReaderAsync>d__18.MoveNext() in /_/src/EFCore.Relational/Storage/RelationalCommand.cs:line 658
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.<ExecuteReaderAsync>d__18.MoveNext() in /_/src/EFCore.Relational/Storage/RelationalCommand.cs:line 719
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.<InitializeReaderAsync>d__21.MoveNext() in /_/src/EFCore.Relational/Query/Internal/SingleQueryingEnumerable.cs:line 401
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.<ExecuteAsync>d__7`2.MoveNext()
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.<MoveNextAsync>d__20.MoveNext() in /_/src/EFCore.Relational/Query/Internal/SingleQueryingEnumerable.cs:line 323
at System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable`1.ConfiguredValueTaskAwaiter.GetResult() in /_/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs:line 154
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.<SingleAsync>d__14`1.MoveNext() in /_/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs:line 138
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.<SingleAsync>d__14`1.MoveNext() in /_/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs:line 150
at Program.<<<Main>$>g__ExecuteQueriesInContext|0_2>d.MoveNext() in G:\Source\repos\DefaultTypeMappingsTests\Program.cs:line 64
at Program.<<<Main>$>g__ExecuteWithSqlServer|0_0>d.MoveNext() in G:\Source\repos\DefaultTypeMappingsTests\Program.cs:line 19
at Program.<<Main>$>d__0.MoveNext() in G:\Source\repos\DefaultTypeMappingsTests\Program.cs:line 6
at Program.<Main>(String[] args)
This exception was originally thrown at this call stack:
System.Convert.ChangeType(object, System.Type, System.IFormatProvider) in Convert.cs
Microsoft.Data.SqlClient.SqlParameter.CoerceValue(object, Microsoft.Data.SqlClient.MetaType, out bool, out bool, bool)
Inner Exception 1:
InvalidCastException: Object must implement IConvertible.
Sqlite:
System.InvalidOperationException
HResult=0x80131509
Message=No mapping exists from object type DefaultTypeMappingsTests.NonGenericWrapper to a known managed provider native type.
Source=Microsoft.Data.Sqlite
StackTrace:
at Microsoft.Data.Sqlite.SqliteValueBinder.Bind() in /_/src/Microsoft.Data.Sqlite.Core/SqliteValueBinder.cs:line 236
at Microsoft.Data.Sqlite.SqliteParameter.Bind(sqlite3_stmt stmt) in /_/src/Microsoft.Data.Sqlite.Core/SqliteParameter.cs:line 225
at Microsoft.Data.Sqlite.SqliteParameterCollection.Bind(sqlite3_stmt stmt) in /_/src/Microsoft.Data.Sqlite.Core/SqliteParameterCollection.cs:line 331
at Microsoft.Data.Sqlite.SqliteCommand.<GetStatements>d__54.MoveNext() in /_/src/Microsoft.Data.Sqlite.Core/SqliteCommand.cs:line 323
at Microsoft.Data.Sqlite.SqliteDataReader.NextResult() in /_/src/Microsoft.Data.Sqlite.Core/SqliteDataReader.cs:line 151
at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior) in /_/src/Microsoft.Data.Sqlite.Core/SqliteCommand.cs:line 312
at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken) in /_/src/Microsoft.Data.Sqlite.Core/SqliteCommand.cs:line 406
at Microsoft.Data.Sqlite.SqliteCommand.<ExecuteDbDataReaderAsync>d__60.MoveNext() in /_/src/Microsoft.Data.Sqlite.Core/SqliteCommand.cs:line 420
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.<ExecuteReaderAsync>d__18.MoveNext() in /_/src/EFCore.Relational/Storage/RelationalCommand.cs:line 658
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.<ExecuteReaderAsync>d__18.MoveNext() in /_/src/EFCore.Relational/Storage/RelationalCommand.cs:line 719
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.<InitializeReaderAsync>d__21.MoveNext() in /_/src/EFCore.Relational/Query/Internal/SingleQueryingEnumerable.cs:line 401
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.<MoveNextAsync>d__20.MoveNext() in /_/src/EFCore.Relational/Query/Internal/SingleQueryingEnumerable.cs:line 323
at System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable`1.ConfiguredValueTaskAwaiter.GetResult() in /_/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs:line 154
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.<SingleAsync>d__14`1.MoveNext() in /_/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs:line 138
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.<SingleAsync>d__14`1.MoveNext() in /_/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs:line 150
at Program.<<<Main>$>g__ExecuteQueriesInContext|0_2>d.MoveNext() in G:\Source\repos\DefaultTypeMappingsTests\Program.cs:line 64
at Program.<<<Main>$>g__ExecuteWithSqlite|0_1>d.MoveNext() in G:\Source\repos\DefaultTypeMappingsTests\Program.cs:line 36
at Program.<<Main>$>d__0.MoveNext() in G:\Source\repos\DefaultTypeMappingsTests\Program.cs:line 6
at Program.<Main>(String[] args)
Include provider and version information
EF Core version: Database provider: Microsoft.EntityFrameworkCore.SqlServer and Microsoft.EntityFrameworkCore.Sqlite Target framework: .NET 8.0 Operating system: Windows 10 & 11 IDE: Visual Studio 2022 17.11.4
Minimal repro:
await using var context = new BlogContext();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
var wrapper = new MyWrapper(8);
_ = await context.Blogs.Where(p => wrapper == p.Id).ToListAsync();
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;Encrypt=false")
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder.DefaultTypeMapping<MyWrapper>().HasConversion<MyWrapperConverter>();
}
private class MyWrapperConverter() : ValueConverter<MyWrapper, int>(v => v.Wrapped, v => new MyWrapper(v));
}
public class Blog
{
public int Id { get; set; }
}
public record MyWrapper(int Wrapped)
{
public static bool operator ==(MyWrapper left, int right) => left.Wrapped == right;
public static bool operator !=(MyWrapper left, int right) => left.Wrapped != right;
}
This is an issue in query translation, SqlParameterExpression does not have a type mapping when the binary expression is processed. But even if it did type mapping inference might not choose the correct type mapping.
Related to https://github.com/dotnet/efcore/issues/30701
when initially constructed, SqlQueryParameters always come without type mapping: https://github.com/dotnet/efcore/blob/59fc95bf505123c79e01aeccecc57ea95b2a5394/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs#L529
and we rely on inference to fill it in. Not a trivial thing to change and scenario is not super common - moving to backlog
@maumar It is a released API that is documented to do one thing and it does not. It is a bug in my playbook, super common or not.
@ADD-David-Antolin This was confirmed as a bug and is prioritized against other bugs depending on impact.