dize

2015-09-12 21 views
11

olarak veritabanında enum kurtarmak için nasıl Bu, bizdize

enter image description here

Int

public class User 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 
    public Type Type { get; set; } 
    public List<Wepon> WeposInList { get; set; } 
    } 

public enum Type 
{ [Description("Zombie")] Zombie, 
    [Description("Human")] Human 
} 

Şu anda kaydediyor verileri bir zombi veya İnsan olabilecek bir türü var benim Modeli Sınıf olduğunu

Verileri İnsan ve Zombi olarak kaydetmek istiyorum int

+1

Numaralandırma statik bir nesnedir, veritabanına kaydetmenin bir anlamı yoktur ... Gerçekten de veritabanındaki öğeleri tanımlamanız ve ardından kodunuzu bir T4 şablonu kullanarak kodlamanız gerekir. –

+4

Bir enum değeri _is_ an int. Bunu gerçekten kaydetmelisin. DB bir dize olarak sahip olmak için bir _very good_ sebebi yoksa .. Hangi sanırım yok. –

+3

@ Pierre-LucPineault: bir int olarak depolamak tehlikeli değil mi? Herkesin yapması gereken, enum'u yeniden sipariş etmemesi ve hemen veritabanınızdaki tüm değerlerin herhangi bir uyarıda bulunmadan yanlış numaraya işaret etmesidir. – Diskdrive

cevap

3

Ben bildiğim kadarıyla bu sorunu vardı ve dürüstçe NH hep beri gibi bunu yapabilir (MS bu özelliği eklemek vermedi neden bilmiyorum. .). Genellikle is gibi const dizeleri sınıfları kullandı neyi

herhangi bir şekilde,:

public static class MyEnum 
{ 
    public const string Foo = "Foo"; 
    public const string Bar = "Bar"; 
} 

public class Client 
{ 

    public string MyVal { get; set; } 

    public Client() 
    { 
     MyVal = MyEnum.Bar; 
    } 

} 

Cons - kadar basit olabilir.

Downsides - gevşek tip denetimi (programlı olarak zorlanabilir olsa da).

Bu sefer daha iddialı bir şey düşünmeye çalıştım. Bu yüzden, Brian tarafından tanımlanan kavramı aldım (örneğin, belirli bir enum'un alan genelinde yaygın olarak kullanıldığı zaman bazı olumsuzlukları vardır).

bir temel bileşeni sınıf değerlerini saklamak için: Ve de .. ben şu çalışma var

[ComplexType] 
public class DbEnum<TEnum> 
{ 
    public string _ { get; set; } 

    public DbEnum() 
    { 
     _ = default(TEnum).ToString(); 
    } 

    protected DbEnum(TEnum value) 
    { 
     _ = value.ToString(); 
    } 

    public TEnum ToEnum() 
    { 
     return _.ToEnum<TEnum>(); 
    } 

    public static implicit operator DbEnum<TEnum>(TEnum value) 
    { 
     return new DbEnum<TEnum>(value); 
    } 

    public static implicit operator TEnum(DbEnum<TEnum> value) 
    { 
     return value.ToEnum(); 
    } 
} 

... EF jenerik türlerini desteklemez hariç .. temelde yeterli olacaktır .. .

Bu gibi bir şey olması gerekir her enum için anlamı ... size kolayca örneğin oluşturulabilir olabilecek bazı kazan-plaka verir

public enum PrivacyLevel 
{ 
    Public, 
    Friends, 
    Private 
} 

public class PrivacyLevelEnum : DbEnum<PrivacyLevel> 
{ 
    public PrivacyLevelEnum() : this(default (PrivacyLevel)) 
    {  
    } 

    public PrivacyLevelEnum(PrivacyLevel value) : base(value) 
    { 
    } 

    public static implicit operator PrivacyLevelEnum(PrivacyLevel value) 
    { 
     return new PrivacyLevelEnum(value); 
    } 

    public static implicit operator PrivacyLevel(PrivacyLevelEnum value) 
    { 
     return value.ToEnum(); 
    } 
} 

T4 şablonları kullanarak.

public class CalendarEntry : Entity 
{ 

    public virtual PrivacyLevelEnum PrivacyLevel { get; set; } = new PrivacyLevelEnum(); 

} 

Ama yerinde örtük dönüştürme beri, sınıf bildirimleri sadece onlar yardımcı türlerinden haberdar olmak şunlardır: nihayet kullanarak size biter

.

+0

Bu yöntemde, string.ToEnum (); - bu – Ken

+0

@Ken evet bir uzantısı yöntemidir - 'ortak statik T ToEnum (bu dizi değeri) { geri (T) Enum.Parse (typeof (T) değeri, doğru); } ' –

3

Onları dizge olarak saklamak iyi bir fikir değil, ancak sizin için tabloları arayabilirsin. ef enum to lookup ile ums ve kullanımı çok kolaydır.

+2

Beğendiğinize sevindim :-) Ayrıca bkz. Http://stackoverflow.com/q/11167665/10245 –

+0

Enum'u nvarchar() 'olarak saklamanın neden iyi bir fikir olmadığını biraz açıklayabilir misiniz? Metin, veritabanındaki bir tam sayıdan daha okunamaz mı? – Blaise

+0

Esneklik ve performans @Blaise – dotctor

1

Ben int olarak depolamak çok daha yararlıdır, çünkü int DB'den çok kolay bir şekilde enum DB'ye.

Eğer arzu ettiğiniz buysa, iki yaklaşım vardır. Veritabanına ("Zombie" olacak) Type.Zombie.ToString() (veya.sırasıyla) kaydedebilirsiniz ya da kullandığınız ve DB'ye kaydettiğiniz DescriptionAttribute değerini elde edebilirsiniz. Açıklama nasıl tanımlanır here açıklanmaktadır. - Bu durumda da "Zombie" olacak, ama Description()'da yazdığınız her şey olabilir.

ToString kullanırsanız, enum örneğini geri almak için Enum.Parse kullanabilirsiniz. Açıklamayı kullanırsanız, o kadar kolay değildir.

+1

Entity Framework şimdi numaralarını destekliyor ve DB'yi enum ilgili değerine çevirmeye gerek yoktur. – dotctor

9

Enonu db'ye bir dize olarak kaydedebilirsiniz ve dotctor'a bunun en iyi fikir olmadığını kabul ediyorum, ancak gerekirse, birkaç değişiklik yapmanız gerekir.

public class User 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 
    public List<Wepon> WeposInList { get; set; } 

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

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

Bu uzantı sınıfını projenize ekleyin.

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

tüm detaylar burada - Hatırladığım kadarıyla http://NoDogmaBlog.bryanhogan.net/2014/11/saving-enums-as-strings-with-entity-framework/

+1

Bunu, veritabanındaki hem etiketi hem de kimliği izlemek için nasıl kullanırdım? Bir rekor getirdiğimde null argüman istisnası alıyorum. – TWilly

+1

[NotMapped] öğesini kaldırmayı deneyin ve db – Bryan

+1

'daki diğer bir sütuna OP sorununun asıl yanıtını ayarlayın. :) – toddmo