dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.68k stars 3.17k forks source link

Improve exception message for instance or inline value converter with compiled model #25738

Closed rlgordey closed 3 years ago

rlgordey commented 3 years ago

I have a Customer Entity configured in my DbContext.ModelBuilder as:

modelBuilder.Entity<Customer>()
    .HasKey(k => k.Custnmbr);

modelBuilder.Entity<Customer>()
    .Property(e => e.Custnmbr)
    .HasConversion(v => v.TrimEnd(), v => v.TrimEnd());

The entity that was scaffolded is:

[Table("RM00101")]    
public class Customer : INotifyPropertyChanged
{
    [Key]
    [Column("CUSTNMBR", TypeName = "char(15)")]
    [StringLength(15)]
    public string Custnmbr { get; set; }
    ...
}

When I run Optimize-DbContext I get this exception:

System.InvalidOperationException: The property 'Customer.Custnmbr' has a value converter configured. Use 'HasConversion' to configure the value converter type.
   at Microsoft.EntityFrameworkCore.Scaffolding.Internal.CSharpRuntimeModelCodeGenerator.Create(IProperty property, Dictionary`2 propertyVariables, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
   at Microsoft.EntityFrameworkCore.Scaffolding.Internal.CSharpRuntimeModelCodeGenerator.CreateEntityType(IEntityType entityType, IndentedStringBuilder mainBuilder, IndentedStringBuilder methodBuilder, SortedSet`1 namespaces, String className, Boolean nullable)
   at Microsoft.EntityFrameworkCore.Scaffolding.Internal.CSharpRuntimeModelCodeGenerator.GenerateEntityType(IEntityType entityType, String namespace, String className, Boolean nullable)
   at Microsoft.EntityFrameworkCore.Scaffolding.Internal.CSharpRuntimeModelCodeGenerator.GenerateModel(IModel model, CompiledModelCodeGenerationOptions options)
   at Microsoft.EntityFrameworkCore.Scaffolding.Internal.CompiledModelScaffolder.ScaffoldModel(IModel model, String outputDir, CompiledModelCodeGenerationOptions options)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.Optimize(String outputDir, String modelNamespace, String contextTypeName)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OptimizeContextImpl(String outputDir, String modelNamespace, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OptimizeContext.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
The property 'Customer.Custnmbr' has a value converter configured. Use 'HasConversion' to configure the value converter type.

Even though it is using 'HasConversion'.

EF Core version: 6.0.0-rc.2.21426.10 Database provider: Microsoft.EntityFrameworkCore.SqlServer Target framework: net6.0 Operating system: Windows 10 IDE: Visual Studio 2022 17.0.0 Preview 3.1

ajcvickers commented 3 years ago

@rlgordey The key part about this message is the word "type" in, "Use 'HasConversion' to configure the value converter type." This means you need to create a ValueConverter type and configure that type in the model, rather than using inline conversion expressions. We will try to make this exception message clearer.

rlgordey commented 3 years ago

@ajcvickers I have tried ...

var converter = new ValueConverter<string, string>(
                v => v.PadRight(15),
                v => v.TrimEnd());

modelBuilder.Entity<Customer>()
    .Property(e => e.Custnmbr)
    .HasConversion(converter);

With the same error.

ajcvickers commented 3 years ago

@rlgordey Hopefully this is clearer:

The property 'Customer.Custnmbr' has a value converter configured using a ValueConverter instance or inline expressions.
Instead, create a type that inherits from ValueConverter and use 'HasConversion<ConverterType>()' or
'HasConversion(Type converterType)' to configure the value converter.