Сопоставить столбец строки в Entity Framework с Enum - PullRequest
20 голосов
/ 16 сентября 2011

Есть ли способ сопоставить строковый столбец с перечислением в Entity Model?

Я сделал это в Hibernate, но не могу понять это в EMF.

Ответы [ 8 ]

21 голосов
/ 24 июля 2014

Возможно, более приятная версия.

Поле OrderStateIdentifier используется как для сериализации JSON, так и для поля базы данных, а OrderState используется в коде только для удобства.

    public string OrderStateIdentifier
    {
        get { return OrderState.ToString(); }
        set { OrderState = value.ToEnum<OrderState>(); }
    }

    [NotMapped]
    [JsonIgnore]
    public OrderState OrderState { get; set; }


public static class EnumHelper
{
    /// <summary>
    /// Converts string to enum value (opposite to Enum.ToString()).
    /// </summary>
    /// <typeparam name="T">Type of the enum to convert the string into.</typeparam>
    /// <param name="s">string to convert to enum value.</param>
    public static T ToEnum<T>(this string s) where T: struct
    {
        T newValue;
        return Enum.TryParse(s, out newValue) ? newValue : default(T);
    }
}
13 голосов
/ 16 сентября 2011

Это некрасиво, но для отображения перечислений в строки я нашел что-то вроде этого:

public virtual string StatusString
{
    get { return Status.ToString(); }
    set { OrderStatus newValue; 
          if (Enum.TryParse(value, out newValue))
          { Status = newValue; }
        }
}

public virtual OrderStatus Status { get; set; } 

OrderStatus - это тип перечислителя, Status - это перечислитель, а StatusString - его строковая версия.

3 голосов
/ 15 ноября 2011

На самом деле, я думаю, что есть другое решение.

То, что мы недавно делали в нашем Проекте, использовало методы расширения.

Я написал два из них, один для Enum и один длясущность, но вот пример:

namespace Foo.Enums
{
    [DataContract]
    public enum EAccountStatus
    { 
        [DataMember]
        Online,
        [DataMember]
        Offline,
        [DataMember]
        Pending
    }

... само перечисление, а теперь методы расширения, содержащие статический класс:

    public static class AccountStatusExtensionMethods
    {

        /// <summary>
        /// Returns the Type as enumeration for the db entity
        /// </summary>
        /// <param name="entity">Entity for which to check the type</param>
        /// <returns>enum that represents the type</returns>
        public static EAccountStatus GetAccountStatus(this Account entity)
        {
            if (entity.AccountStatus.Equals(EAccountStatus.Offline))
            {
                return EAccountStatus.Offline;
            }
            else if (entity.AccountStatus.Equals(EAccountStatus.Online))
            {
                return EAccountStatus.Online;
            }
            else if (entity.AccountStatus.Equals(EAccountStatus.Pending))
            {
                return EAccountStatus.Pending;
            }
            throw new System.Data.Entity.Validation.DbEntityValidationException(
                "Unrecognized AccountStatus was set, this is FATAL!");
        }

... метод расширения длятип сущности и удобный метод для более короткой типизации:

        /// <summary>
        /// Gets the String representation for this enums choosen 
        /// </summary>
        /// <param name="e">Instance of the enum chosen</param>
        /// <returns>Name of the chosen enum in String representation</returns>
        public static String GetName(this EAccountStatus e)
        {
            return Enum.GetName(typeof(EAccountStatus), e);
        }
    }
}

... и, наконец, использование:

// to set always the same, mappable strings:
db.AccountSet.Single(m => m.Id == 1).Status = EAccountStatus.Online.GetName();

// to get the enum from the actual Entity you see:
EAccountStatus actualStatus = db.AccountSet.Single(m => m.Id == 1).GetAccountStatus();

Теперь вам просто нужно "использовать Foo.Enums;"и вы можете вызывать методы как для объекта, так и для перечисления.И, что еще лучше, в некоторых видах оберток для ваших сущностей вы также можете выполнять плавное распределение между разными типами, представляющими одно и то же в больших проектах.

Единственное, на что стоит обратить внимание, это то, что вам иногда приходится выполнять метод расширения, прежде чем передать выражение Linq в Linq.Проблема в том, что Linq не может выполнить метод расширения в своем собственном контексте ...

Может быть, просто альтернатива, но мы сделали это так, потому что это дает вам большую гибкость в том, как получить вещидля юридических лиц.Вы можете легко написать расширение, чтобы получать учетные записи актуальных продуктов в ShoppingCart ...

Greetings, Kjellski

2 голосов
/ 04 февраля 2015

Альтернативой является использование статического класса со строковыми константными полями вместо перечислений.

Например:

public class PocoEntity
{
    public string Status { get; set; }
}

public static class PocoEntityStatus
{
    public const string Ok = "ok";
    public const string Failed = "failed";
}

Для дополнительной проверки на стороне базы данных вы можете добавить проверочное ограничение, чтобы убедиться, что столбец является ожидаемым значением (вы можете сделать это и при сопоставлении с перечислением, но так как свойство является просто строкой, это помогает обеспечить потребитель вашего API устанавливает значение правильно).

ALTER TABLE [PocoEntity]
    ADD CONSTRAINT [CHK_PocoEntity_Status]
    CHECK ([Status] in ('ok', 'failed'));
1 голос
/ 26 июня 2019

Вы можете сделать:

Украсить свойство Enum в вашем классе как текстовый столбец

[Column(TypeName = "nvarchar(50)")]
public FileTypes FileType { get; set; }

ИЛИ

в вашем классе DatabaseContext, переопределитьOnModelCreating и добавьте:

modelBuilder
  .Entity<File>()
  .Property(e => e.FileType)
  .HasConversion(new EnumToStringConverter<FileTypes>());
1 голос
/ 05 октября 2017

Если вы хотите отобразить значение перечисления в другую соответствующую строку (например, аббревиатуру), вы можете использовать этот подход:

public class MinhaClasse
{
    public string CodTipoCampo { get; set; }

    [NotMapped]
    public TipoDado TipoCampo
    {
        get => DictValorTipoDado.SingleOrDefault(e => e.Value == CodTipoCampo).Key;
        set => CodTipoCampo = DictValorTipoDado[value];
    }

    private Dictionary<TipoDado, string> DictValorTipoDado = new Dictionary<TipoDado, string>()
    {
        { TipoDado.Texto, "T" },
        { TipoDado.Numerico, "N" },
        { TipoDado.Data, "D" }
    };

    public enum TipoDado { Texto, Numero, Data }
}
1 голос
/ 19 февраля 2015
0 голосов
/ 01 мая 2015

У меня была такая же проблема.Я придумал решение, но я не совсем доволен им.

Мой класс Person имеет перечисление Gender, и я использую аннотации данных для сопоставления строки с базой данных и игнорирования перечисления.

public class Person
{
    public int PersonID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    [Column("Gender")]
    public string GenderString
    {
        get { return Gender.ToString(); }
        private set { Gender = EnumExtensions.ParseEnum<Gender>(value); }
    }

    [NotMapped]
    public Gender Gender { get; set; }
}

здесь используется метод расширения дляполучить правильное перечисление из строки.

public class EnumExtensions
{
    public static T ParseEnum<T>(string value)
    {
        return (T)Enum.Parse(typeof(T), value, true);
    }
}

Я написал в блоге об этом - http://nodogmablog.bryanhogan.net/2014/11/saving-enums-as-strings-with-entity-framework/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...