Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Map enum to string set default enum value via HasDefaultValueSql #19843

Closed
wangpengxpy opened this issue Feb 8, 2020 · 11 comments
Closed

Map enum to string set default enum value via HasDefaultValueSql #19843

wangpengxpy opened this issue Feb 8, 2020 · 11 comments
Labels
closed-no-further-action The issue is closed and no further action is planned. customer-reported

Comments

@wangpengxpy
Copy link

First,mapping enum to tinyint is fine,code show as below

    public class Blog
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public Color Color { get; set; }
        public List<Post> Posts { get; set; }
    }

    public enum Color : byte
    {
        Black = 1,
        Red,
        Blue
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
         modelBuilder.Entity<Blog>(b => 
         {
              b.Property(p => p.Color).HasDefaultValueSql("1");
         });
    }

but map to string can not work,code show as below

    public class Blog
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public Color Color { get; set; }
        public List<Post> Posts { get; set; }
    }

    public enum Color
    {
        Black = 1,
        Red,
        Blue
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
         modelBuilder.Entity<Blog>(b => 
         {
              b.Property(p => p.Color).HasColumnType("VARCHAR(20)").HasDefaultValueSql("Black");
        });
    }

The follow exception:

Microsoft.Data.SqlClient.SqlException: "The name" Black "is not allowed in this context. Valid expressions include constants, constant expressions, and variables (in some contexts). Column names are not allowed.

More details:

EF Core version: 3.1.1
Database provider: (Microsoft.EntityFrameworkCore.SqlServer)
Target framework: (.NET Core 3.1)
Operating system: Windows 10
IDE: (Visual Studio 2019 16.4.4)

@wangpengxpy wangpengxpy changed the title Map enum to string Set default enum value via HasDefaultValueSql Map enum to string set default enum value via HasDefaultValueSql Feb 8, 2020
@ajcvickers
Copy link
Member

@wangpengxpy HasDefaultValueSql requires the raw SQL literal expression. Try .HasDefaultValueSql("'Black'"), or use .HasDefaultValue("Black") which will create the SQL literal from the given string.

@ajcvickers ajcvickers added closed-no-further-action The issue is closed and no further action is planned. and removed type-bug labels Feb 10, 2020
@wangpengxpy
Copy link
Author

@ajcvickers thanks your reply
use HasDefaultValueSql("'Black'") works,but try HasDefaultValue("Black") before and will throw an exception:System.InvalidOperationException:“Cannot set default value 'Black' of type 'System.String' on property 'Color' of type 'Model.Color' in entity type 'Blog'.” ,so I think using HasDefaultValue support is the best way in this case.Does it need improvement?

@ajcvickers ajcvickers reopened this Feb 13, 2020
@ajcvickers ajcvickers removed the closed-no-further-action The issue is closed and no further action is planned. label Feb 13, 2020
@ajcvickers
Copy link
Member

@wangpengxpy Thanks for the additional info.

Team: I can reproduce the issue with HasDefaultValue("Black"). Stack trace:

"C:\Program Files\dotnet\dotnet.exe" C:/Stuff/MyRepros/AllTogetherNow/Local/bin/Debug/netcoreapp3.1/Local.dll
Unhandled exception. System.InvalidOperationException: Cannot set default value 'Black' of type 'System.String' on property 'Color' of type 'Color' in entity type 'Blog'.
   at Microsoft.EntityFrameworkCore.RelationalPropertyExtensions.ConvertDefaultValue(IProperty property, Object value)
   at Microsoft.EntityFrameworkCore.RelationalPropertyExtensions.SetDefaultValue(IMutableProperty property, Object value)
   at Microsoft.EntityFrameworkCore.RelationalPropertyBuilderExtensions.HasDefaultValue(PropertyBuilder propertyBuilder, Object value)
   at Microsoft.EntityFrameworkCore.RelationalPropertyBuilderExtensions.HasDefaultValue[TProperty](PropertyBuilder`1 propertyBuilder, Object value)
   at SomeDbContext.<>c.<OnModelCreating>b__0_0(EntityTypeBuilder`1 b) in C:\Stuff\MyRepros\AllTogetherNow\Local\Local.cs:line 49
   at Microsoft.EntityFrameworkCore.ModelBuilder.Entity[TEntity](Action`1 buildAction)
   at SomeDbContext.OnModelCreating(ModelBuilder modelBuilder) in C:\Stuff\MyRepros\AllTogetherNow\Local\Local.cs:line 47
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelCustomizer.Customize(ModelBuilder modelBuilder, DbContext context)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
   at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__7_3(IServiceProvider p)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
   at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
   at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance()
   at Microsoft.EntityFrameworkCore.Infrastructure.Internal.InfrastructureExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.get_Dependencies()
   at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.EnsureDeleted()
   at ThreeOne.Main() in C:\Stuff\MyRepros\AllTogetherNow\Local\Local.cs:line 22

@wangpengxpy
Copy link
Author

@ajcvickers,thanks for reopening,I hope this problem can be improved

@ajcvickers
Copy link
Member

@wangpengxpy The team pointed out to me that my suggestion to use .HasDefaultValue("Black") was incorrect. Because the property is an enum in the model, the enum value should be used here. For example, .HasDefaultValue(Color.Black). EF then does the conversion to string based on the mapping.

@ajcvickers ajcvickers added the closed-no-further-action The issue is closed and no further action is planned. label Feb 17, 2020
@ajcvickers ajcvickers reopened this Oct 16, 2022
@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Oct 16, 2022
@johnwc
Copy link

johnwc commented Jan 3, 2024

@ajcvickers @tonysneed what about when you use scaffolding with a db first scenario, and use handlebars to set an entity's property to an enum? EF scaffolding automatically applies the .HasDefaultValue(0) to the property in OnModelCreating and throws the InvalidOperationException immediately.

@ErikEJ
Copy link
Contributor

ErikEJ commented Jan 3, 2024

@johnwc That would be a Handlebars issue

@johnwc
Copy link

johnwc commented Jan 3, 2024

@ErikEJ How so? The error is occurring so early, I cannot overwrite the default value within the OnModelCreatingPartial method with the actual enum value. And there is no way for me to tell the scaffolding to not generate HasDefaultValue calls.

@ErikEJ
Copy link
Contributor

ErikEJ commented Jan 3, 2024

@johnwc Maybe you should consider T4 templates?

@johnwc
Copy link

johnwc commented Jan 3, 2024

@ErikEJ do you have an example repo I can check out T4 templates with ef core scaffolding? What is the purpose of HasDefaultValue being called anyways for a db first scaffold entity? Why does EF need to know what the default value is, when the database is going to apply it anyways?

@ErikEJ
Copy link
Contributor

ErikEJ commented Jan 3, 2024

I have some samples here: ErikEJ/EFCorePowerTools#1499

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-no-further-action The issue is closed and no further action is planned. customer-reported
Projects
None yet
Development

No branches or pull requests

4 participants