将实体框架中的字符串列映射到枚举

本文关键字:映射 枚举 字符串 实体 框架 | 更新日期: 2023-09-27 18:08:49

是否有一种方法将字符串列映射到实体模型中的枚举?

我已经在Hibernate中这样做了,但是无法在EMF中弄清楚。

将实体框架中的字符串列映射到枚举

可能是更好的版本。

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);
    }
}

它很丑,但是对于将枚举映射到字符串,我发现了这样的东西:

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是它的字符串版本。

你可以这样做:

将类中的Enum属性装饰为文本列

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

DatabaseContext类中,覆盖OnModelCreating并添加:

modelBuilder
  .Entity<File>()
  .Property(e => e.FileType)
  .HasConversion(new EnumToStringConverter<FileTypes>());

另一种方法是使用带有字符串const字段的静态类来代替枚举。

例如:

public class PocoEntity
{
    public string Status { get; set; }
}
public static class PocoEntityStatus
{
    public const string Ok = "ok";
    public const string Failed = "failed";
}

对于在数据库端添加的验证,您可以添加一个检查约束来验证该列是否是期望的值(当映射到enum时也可以这样做,但由于属性只是一个字符串,这有助于确保api的消费者正确设置值)。

ALTER TABLE [PocoEntity]
    ADD CONSTRAINT [CHK_PocoEntity_Status]
    CHECK ([Status] in ('ok', 'failed'));

实际上我认为还有另一种解决方案。

我们最近在项目中使用的是扩展方法。

我写了两个,一个用于枚举,一个用于实体,但这里是示例:

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…

问候,Kjellski

我也遇到了同样的问题。我想到了一个解决办法,但我并不完全满意。

我的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; }
}

这里是从字符串中获得正确enum的扩展方法。

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/

这是EF7的路线图:https://github.com/aspnet/EntityFramework/issues/242

你可以投票支持它:http://data.uservoice.com/forums/72025-entity-framework-feature-suggestions/suggestions/2639292-simple-type-mapping-or-mapped-type-conversion-sup

如果您想将枚举值映射到另一个对应的字符串(例如缩写),您可以使用以下方法:

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 }
}