2012-06-23 49 views
24

我想定義一個枚舉EF5使用,以及相應的查找表。我知道EF5現在支持枚舉,但是開箱即用,它似乎只在對象級別支持這一點,並且默認情況下不會爲這些查找值添加表。EF5代碼首先枚舉和查找表

例如,我有一個用戶實體:

public class User 
{ 
    int Id { get; set; } 
    string Name { get; set; } 
    UserType UserType { get; set; } 
} 

而且一個UserType枚舉:

public enum UserType 
{ 
    Member = 1, 
    Moderator = 2, 
    Administrator = 3 
} 

我想爲數據庫生成創建一個表,像這樣:

create table UserType 
(
    Id int, 
    Name nvarchar(max) 
) 

這可能嗎?

+0

用戶語音爲http://data.uservoice.com/forums/72025-entity-framework-feature-suggestions/suggestions/2683498-enhance-enums-by-創建一個查找表與 –

回答

13

的工作流程是不能直接。 EF支持與.NET相同級別的枚舉,因此枚舉值只是命名爲integer =>類中的enum屬性始終是數據庫中的整數列。如果你想擁有表格,你需要在User中用你自己的數據庫初始化器中的外鍵手動創建它並填充枚舉值。

我做了一些proposal on user voice允許更復雜的映射。如果您發現它很有用,您可以爲投標投票。

+1

謝謝拉迪斯拉夫。我已經提出了你的建議。 –

+1

@Ladislav Mrnka,EF的Enum支持不僅限於整數。 「 」枚舉可以具有以下基本類型:Byte,Int16,Int32,Int64或SByte。「 https://msdn.microsoft.com/en-us/data/hh859576 – itanex

-2

要定製你的代

1. Copy your default template of generation TablePerTypeStrategy 

Location : \Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\DBGen. 

2. Add custom activity who realize your need (Workflow Foundation) 

3. Modify your section Database Generation Workflow in your project EF 
+0

在70-516認證你有這個問題的答案 –

8

我寫了一個小助手類,它爲UserEntities類中指定的枚舉創建數據庫表。它還在引用枚舉的表上創建一個外鍵。

所以在這裏,它是:使用

public class EntityHelper 
{ 

    public static void Seed(DbContext context) 
    { 
     var contextProperties = context.GetType().GetProperties(); 

     List<PropertyInfo> enumSets = contextProperties.Where(p =>IsSubclassOfRawGeneric(typeof(EnumSet<>),p.PropertyType)).ToList(); 

     foreach (var enumType in enumSets) 
     { 
      var referencingTpyes = GetReferencingTypes(enumType, contextProperties); 
      CreateEnumTable(enumType, referencingTpyes, context); 
     } 
    } 

    private static void CreateEnumTable(PropertyInfo enumProperty, List<PropertyInfo> referencingTypes, DbContext context) 
    { 
     var enumType = enumProperty.PropertyType.GetGenericArguments()[0]; 

     //create table 
     var command = string.Format(
      "CREATE TABLE {0} ([Id] [int] NOT NULL,[Value] [varchar](50) NOT NULL,CONSTRAINT pk_{0}_Id PRIMARY KEY (Id));", enumType.Name); 
     context.Database.ExecuteSqlCommand(command); 

     //insert value 
     foreach (var enumvalue in Enum.GetValues(enumType)) 
     { 
      command = string.Format("INSERT INTO {0} VALUES({1},'{2}');", enumType.Name, (int)enumvalue, 
            enumvalue); 
      context.Database.ExecuteSqlCommand(command); 
     } 

     //foreign keys 
     foreach (var referencingType in referencingTypes) 
     { 
      var tableType = referencingType.PropertyType.GetGenericArguments()[0]; 
      foreach (var propertyInfo in tableType.GetProperties()) 
      { 
       if (propertyInfo.PropertyType == enumType) 
       { 
        var command2 = string.Format("ALTER TABLE {0} WITH CHECK ADD CONSTRAINT [FK_{0}_{1}] FOREIGN KEY({2}) REFERENCES {1}([Id])", 
         tableType.Name, enumProperty.Name, propertyInfo.Name 
         ); 
        context.Database.ExecuteSqlCommand(command2); 
       } 
      } 
     } 
    } 

    private static List<PropertyInfo> GetReferencingTypes(PropertyInfo enumProperty, IEnumerable<PropertyInfo> contextProperties) 
    { 
     var result = new List<PropertyInfo>(); 
     var enumType = enumProperty.PropertyType.GetGenericArguments()[0]; 
     foreach (var contextProperty in contextProperties) 
     { 

      if (IsSubclassOfRawGeneric(typeof(DbSet<>), contextProperty.PropertyType)) 
      { 
       var tableType = contextProperty.PropertyType.GetGenericArguments()[0]; 

       foreach (var propertyInfo in tableType.GetProperties()) 
       { 
        if (propertyInfo.PropertyType == enumType) 
         result.Add(contextProperty); 
       } 
      } 
     } 

     return result; 
    } 

    private static bool IsSubclassOfRawGeneric(Type generic, Type toCheck) 
    { 
     while (toCheck != null && toCheck != typeof(object)) 
     { 
      var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck; 
      if (generic == cur) 
      { 
       return true; 
      } 
      toCheck = toCheck.BaseType; 
     } 
     return false; 
    } 

    public class EnumSet<T> 
    { 
    } 
} 

代碼:

public partial class UserEntities : DbContext{ 
    public DbSet<User> User { get; set; } 
    public EntityHelper.EnumSet<UserType> UserType { get; set; } 

    public static void CreateDatabase(){ 
     using (var db = new UserEntities()){ 
      db.Database.CreateIfNotExists(); 
      db.Database.Initialize(true); 
      EntityHelper.Seed(db); 
     } 
    } 

} 
+0

作品一種享受。我的修改 - 「姓名」作爲第二列,並拆分枚舉名稱之前存儲與正則表達式 - http://stackoverflow.com/a/155487/10245 –

1

我創建了一個包,它

https://www.nuget.org/packages/SSW.Data.EF.Enums/1.0.0

使用

EnumTableGenerator.Run("your object context", "assembly that contains enums"); 

「你的對象 - 背景」 - 是你的EntityFramework的DbContext 「組件包含枚舉」 - 包含您的枚舉

呼叫EnumTableGenerator.Run作爲種子的部分功能組件。這將在sql server中爲每個Enum創建表並使用正確的數據填充它。

+1

你需要發佈更多信息,這是做什麼,以及什麼時候做上面的電話。一個更具體的例子,比如DbContext應該是怎樣的結構,在哪裏放置枚舉等,也是有幫助的。 –

+0

它似乎也缺少許可證和源代碼的鏈接,這可能會對某些項目造成問題。 –

+0

對於獎勵積分,我無法讓它繼續工作。它運行時沒有錯誤,但沒有創建查找表。 –

1

我已經包含了這個答案,因爲我已經從@HerrKater

做了一些額外的變化我做了一個小除了Herr Kater's Answer(也是基於蒂姆·阿貝爾的評論)。更新是使用一種方法從DisplayName屬性獲取枚舉值,如果存在,則分割PascalCase枚舉值。

private static string GetDisplayValue(object value) 
{ 
    var fieldInfo = value.GetType().GetField(value.ToString()); 

    var descriptionAttributes = fieldInfo.GetCustomAttributes(
    typeof(DisplayAttribute), false) as DisplayAttribute[]; 

    if (descriptionAttributes == null) return string.Empty; 
    return (descriptionAttributes.Length > 0) 
    ? descriptionAttributes[0].Name 
    : System.Text.RegularExpressions.Regex.Replace(value.ToString(), "([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))", "$1 "); 
} 

更新杜林Katers例如調用的方法:

command = string.Format("INSERT INTO {0} VALUES({1},'{2}');", enumType.Name, (int)enumvalue, 
             GetDisplayValue(enumvalue)); 

枚舉實例

public enum PaymentMethod 
{ 
    [Display(Name = "Credit Card")] 
    CreditCard = 1, 

    [Display(Name = "Direct Debit")] 
    DirectDebit = 2 
}