2012-06-23 6 views
24

Ich würde gerne eine enum für EF5 zu verwenden, und eine entsprechende Nachschlagetabelle definieren. Ich weiß, dass EF5 jetzt Enums unterstützt, aber es scheint, als würde es dies nur auf Objektebene unterstützen und fügt standardmäßig keine Tabelle für diese Lookup-Werte hinzu.EF5-Code Erste Enums und Lookup-Tabellen

Zum Beispiel habe ich eine User-Einheit:

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

Und eine Usertype Enumeration:

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

ich für Datenbank-Generation möchte eine Tabelle zu erstellen, so etwas wie:

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

Ist das möglich?

+0

Benutzer Stimme für die in EF http://data.uservoice.com/forums/72025-entity-framework-feature-suggestions/suggestions/2683498-enhance-enums-by- creating-a-lookup-table-with-the –

Antwort

13

Es ist nicht direkt möglich gestalten. EF unterstützt Enums auf der gleichen Ebene wie .NET, so dass der Enum-Wert nur den Namen integer => hat. Enum-Eigenschaft in der Klasse ist immer eine Integer-Spalte in der Datenbank. Wenn Sie auch eine Tabelle haben möchten, müssen Sie sie manuell in Ihrem eigenen Datenbankinitialisierer zusammen mit dem Fremdschlüssel in User anlegen und mit Enum-Werten füllen.

Ich habe einige proposal on user voice erstellt, um komplexere Zuordnungen zu ermöglichen. Wenn Sie es nützlich finden, können Sie für den Vorschlag stimmen.

+1

Danke Ladislav. Ich habe Ihren Vorschlag neu gefasst. –

+1

@Ladislav Mrnka, die Enum-Unterstützung von EF ist nicht nur auf Integer beschränkt. "Enumeration kann die folgenden zugrunde liegenden Typen haben: Byte, Int16, Int32, Int64 oder SByte." https://msdn.microsoft.com/en-us/data/hh859576 – itanex

-2

müssen Sie Ihren Workflow von Generation

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

In 70-516 Zertifizierung haben Sie Antwort zu diesem Thema –

8

Ich schrieb eine kleine Hilfsklasse, die eine Datenbanktabelle für die in der UserEntities-Klasse angegebenen Aufzählungen erstellt. Es erstellt auch einen Fremdschlüssel in den Tabellen, die auf die Enumeration verweisen.

hier So ist es:

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

mit dem Code:

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

Funktioniert ein Vergnügen. Meine Änderungen - "Name" als die zweite Spalte, und teilen Sie die Enum-Namen vor dem Speichern mit Regex - http://StackOverflow.com/a/155487/10245 –

1

Ich habe ein Paket für sie

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

Nutzung erstellt

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

„Ihr Objekt Kontext“ - ist Ihr EntityFramework DbContext „Assembly, die Aufzählungen enthält“ - eine Baugruppe, die Ihre Aufzählungen

Anruf EnumTableGenerator.Run als Teil Ihrer Samen Funktion enthält. Dies erstellt Tabellen in SQL-Server für jede Enum und füllen sie mit korrekten Daten.

+1

Sie müssen mehr Informationen darüber, was dies tut, und wann zu machen der obige Anruf. Ein konkreteres Beispiel, wie der DbContext strukturiert sein soll, wo Enums usw. platziert werden, wäre ebenfalls hilfreich. –

+0

Es scheint auch eine Lizenz und eine Verbindung zum Quellcode zu fehlen, die für einige Projekte problematisch sein könnte. –

+0

Und für Bonuspunkte kann ich es sowieso nicht zur Arbeit bringen. Es wird ohne Fehler ausgeführt, aber keine der Nachschlagetabellen wird erstellt. –

1

Ich habe diese Antwort enthalten, da ich einige zusätzliche Änderungen von @HerrKater gemacht haben

ich eine kleine Ergänzung zu Herr Kater's Answer (auch auf Tim Abell Kommentar basiert) gemacht. Das Update besteht darin, eine Methode zu verwenden, um den Enum-Wert aus dem DisplayName-Attribut abzurufen, falls vorhanden, andernfalls den PascalCase-Enumerationswert zu teilen.

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

aktualisieren Herr Katers Beispiel die Methode aufzurufen:

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

Enum Beispiel

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

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

Hier ist ein nuget Paket, das ich früher gemacht, dass erzeugt Lookup-Tabellen und wendet Fremdschlüssel und hält die Nachschlagetabellenzeilen synchron mit der Enumeration:

https://www.nuget.org/packages/ef-enum-to-lookup

Fügen Sie das Ihrem Projekt hinzu und rufen Sie die Apply-Methode auf.

Dokumentation auf GitHub: https://github.com/timabell/ef-enum-to-lookup

+7

Pure ** EF ** - funk brilliant. Zeitraum. – Hallmanac

+2

Erstaunlich, danke. Ich wünschte, ich könnte geben +10 – Andrey

+1

Sie sind herzlich willkommen :-) –