EntityFrameworkCore есть ли способ создать EnumToStringConverter без передачи типа enum как универсального?

Я пытаюсь использовать EntityFrameworkCore ORM для взаимодействия со своими базами данных. По умолчанию EntityFrameworkCore, похоже, хранит перечисление как int вместо строки.

Однако я хотел бы сохранить значение в базе данных в виде строки. Я вижу, что EntityFrameworkCore поставляется с конвертером под названием EnumToStringConverter.

Я пытаюсь использовать отражение для настройки построителя моделей, поэтому мне не нужно вручную создавать каждую модель.

Проблема, с которой я сталкиваюсь, заключается в том, что EnumToStringConverter принимает общий тип, который должен быть enum. Но поскольку я пытаюсь использовать здесь отражение, я не могу передать тип перечисления при создании преобразователя.

Вот как выглядит мой код до сих пор

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    // Get all DbSet<> properties that are defined in the DbContext
    var modelTypes = typeof(DataContext).GetProperties()
                                        .Where(x => x.PropertyType.IsGenericType && x.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>))
                                        .Select(x => x.PropertyType.GetGenericArguments().First())
                                        .ToList();

    foreach (Type modelType in modelTypes)
    {
        var properties = modelType.GetProperties();

        foreach (var property in properties)
        {
            if (IsPrimaryKey(property))
            {
                // At this point we know that the property is a primary key
                modelBuilder.Entity(modelType)
                            .Property(property.Name)
                            .UseSqlServerIdentityColumn()
                            .Metadata.BeforeSaveBehavior = PropertySaveBehavior.Ignore;

                continue;
            }

            if (property.PropertyType.IsEnum)
            {
                // At this point we know that the property is an enum.
                // Add the EnumToStringConverter converter to the property so that
                // the value is stored in the database as a string instead of number 
                var converter = new EnumToStringConverter(); // if somehow I can change this code to something like var `new EnumToStringConverter(property.PropertyType);` the code would work

                modelBuilder.Entity(modelType)
                            .Property(property.Name)
                            .HasConversion(converter);

                continue;
            }

        }
    }
}

Единственная проблема с приведенным выше кодом заключается в том, как EnumToStringConverter построен. Если каким-то образом я могу предоставить Type конструктору EnumToStringConverter вместо передачи его в качестве общего аргумента, который решит проблему.


person Junior    schedule 15.06.2018    source источник


Ответы (2)


Как описано в разделе Предопределенные преобразования раздел документации:

Для обычных преобразований, для которых существует встроенный преобразователь, нет необходимости указывать преобразователь явно. Вместо этого просто укажите, какой тип поставщика следует использовать, и EF автоматически будет использовать соответствующий встроенный преобразователь. Преобразование Enum в строку используется в качестве примера выше, но EF фактически сделает это автоматически, если настроен тип поставщика:

далее пример.

После этого вы можете просто использовать:

if (property.PropertyType.IsEnum)
{
    // At this point we know that the property is an enum.
    // Add the EnumToStringConverter converter to the property so that
    // the value is stored in the database as a string instead of number 
    modelBuilder.Entity(modelType)
        .Property(property.Name)
        .HasConversion<string>(); // <--

    continue;
}
person Ivan Stoev    schedule 15.06.2018
comment
Это сделало это. я пропустил его - person Junior; 15.06.2018
comment
Как сделать это по умолчанию, чтобы не писать 200 раз? - person Jeremy Holovacs; 22.02.2019
comment
@JeremyHolovacs, вы можете сделать это так: stackoverflow.com/questions/50727860/ просто измените внутреннюю часть кода на ответ отсюда. Но если вы спросите об этом в отдельном вопросе SO, я буду рад дать вам точный ответ! - person Dominik; 08.04.2019
comment
или в качестве атрибута поместите [Column(TypeName = nvarchar(32))] в свойство enum. это автоматически сохранит его как строку. - person Sven Krauter; 20.04.2020

искал то же самое, но не хотел использовать свободный подход.

поместите следующее в ваше свойство перечисления.

 [Column(TypeName = "nvarchar(32)")] 

это автоматически сохранит его как строку. если он помещен в базовый класс, это относится ко всем производным объектам.

вы также можете зарегистрировать конфигурацию типа

public class BaseEntityTypeConfiguration : IEntityTypeConfiguration<BaseEntity>
{
    public void Configure(EntityTypeBuilder<BaseEntity> builder)
    {
        builder.Property(p => p.YourEnumProp).HasConversion<string>();
    }
}

затем вы регистрируете его в modelBuilder

mb.ApplyConfiguration(new BaseEntityTypeConfiguration());
person Sven Krauter    schedule 20.04.2020