Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EF Core 2.0 Enums stored as string

I was able to store an enum as a string in the database.

builder.Entity<Company>(eb =>
{
    eb.Property(b => b.Stage).HasColumnType("varchar(20)");
});

But when it comes time to query EF doesn't know to parse the string into an enum. How can I query like so:

context
    .Company
        .Where(x => x.Stage == stage)

This is the exception: Conversion failed when converting the varchar value 'Opportunity' to data type int

like image 466
Brad Firesheets Avatar asked Dec 08 '17 19:12

Brad Firesheets


3 Answers

Value Conversions feature is new in EF Core 2.1.

Value converters allow property values to be converted when reading from or writing to the database. This conversion can be from one value to another of the same type (for example, encrypting strings) or from a value of one type to a value of another type (for example, converting enum values to and from strings in the database.)

public class Rider
{
    public int Id { get; set; }
    public EquineBeast Mount { get; set; }
}

public enum EquineBeast
{
    Donkey,
    Mule,
    Horse,
    Unicorn
}

You can use own conversion

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<Rider>()
        .Property(e => e.Mount)
        .HasConversion(
            v => v.ToString(),
            v => (EquineBeast)Enum.Parse(typeof(EquineBeast), v));
}

or Built-in converter

var converter = new EnumToStringConverter<EquineBeast>();

modelBuilder
    .Entity<Rider>()
    .Property(e => e.Mount)
    .HasConversion(converter);
like image 144
szydzik Avatar answered Nov 13 '22 00:11

szydzik


You can use this to convert all the Enum of all the properties of all the entities into a string and vice versa :

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using System;

namespace MyApp
{
    public class DatabaseContext : DbContext
    {
        public DbSet<UserContext> Users { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            // Configure your model here
        }

        protected override void OnModelCreating(ModelBuilder model)
        {
            foreach (var entityType in model.Model.GetEntityTypes())
            {
                foreach (var property in entityType.GetProperties())
                {
                    if (property.ClrType.BaseType == typeof(Enum))
                    {
                        var type = typeof(EnumToStringConverter<>).MakeGenericType(property.ClrType);
                        var converter = Activator.CreateInstance(type, new ConverterMappingHints()) as ValueConverter;

                        property.SetValueConverter(converter);
                    }
                }
            }
        }
    }
}
like image 43
pedrodel Avatar answered Nov 12 '22 22:11

pedrodel


You can do this much more easily with a one-liner attribute.

[Column(TypeName = "nvarchar(24)")]
public EquineBeast Mount { get; set; }

That's all you need to do! This is a string to enum value conversion by explicitly specifying the database column type as an attribute on the property. Documentation

I had gotten the same error as the OP because I was originally using the [MaxLength] attribute instead.

(The original question is for EF 2.0, and this feature starts in EF 2.1 as others mention in their answers. But google lead me here so I decided to add a useful answer.)

like image 42
Jess Avatar answered Nov 12 '22 22:11

Jess