2012-06-23 11 views
24

Chciałbym zdefiniować wyliczenie dla EF5 do użycia i odpowiadającą tabelę odnośników. Wiem, że EF5 obsługuje teraz wyliczenia, ale gotowe, wygląda na to, że obsługuje tylko to na poziomie obiektu i domyślnie nie dodaje tabeli dla tych wartości wyszukiwania.Kod EF5 Pierwsze tablice wyliczeń i wyszukiwania

Na przykład mam podmiot użytkownika:

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

a enum UserType:

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

chciałbym do generowania bazy danych, aby utworzyć tabelę, coś jak:

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

Czy to możliwe?

+0

użytkownik głosem, że w EF http://data.uservoice.com/forums/72025-entity-framework-feature-suggestions/suggestions/2683498-enhance-enums-by- tworzenie-look-table-with-the –

Odpowiedz

13

nie jest to bezpośrednio możliwe. EF obsługuje wyliczenia na tym samym poziomie co .NET, więc wartość wyliczeniowa jest po prostu nazwana liczbą całkowitą => właściwość enum w klasie jest zawsze całkowitą kolumną w bazie danych. Jeśli chcesz mieć również tabelę, musisz utworzyć ją ręcznie w swoim inicjatorze bazy danych razem z kluczem obcym pod numerem User i wypełnić go wartościami wyliczeniowymi.

Zrobiłem trochę proposal on user voice, aby umożliwić bardziej złożone odwzorowania. Jeśli uznasz to za przydatne, możesz głosować na propozycję.

+1

Dzięki Ladislav. Zawarłem twoją propozycję. –

+1

@ Ladislav Mrnka, Enum wsparcie EF nie ogranicza się tylko do liczby całkowitej. "wyliczenie może mieć następujące typy bazowe: Byte, Int16, Int32, Int64 lub SByte." https://msdn.microsoft.com/en-us/data/hh859576 – itanex

-2

trzeba dostosować swój obieg generacji

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

W certyfikacji 70-516 masz odpowiedź na ten temat –

8

Napisałem małą klasę pomocniczą, która tworzy tabelę bazy danych dla wyliczeń określonych w klasie UserEntities. Tworzy również klucz obcy w tabelach odnoszących się do wyliczenia.

Więc to jest tutaj:

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

przy użyciu kodu:

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

Działa na poczęstunek. Moje modyfikacje - "Nazwa" jako druga kolumna i rozdziel nazwy enum przed zapisaniem za pomocą regex - http://stackoverflow.com/a/155487/10245 –

1

Stworzyłem pakiet za nim

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

Zastosowanie

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

„context obiekt” - to EntityFramework DbContext „zespół, który zawiera teksty stałe” - zespół, który zawiera teksty stałe

połączeń EnumTableGenerator.Run jako część funkcji nasion. Spowoduje to utworzenie tabel w serwerze sql dla każdego Enum i wypełnienie go poprawnymi danymi.

+1

Musisz opublikować więcej informacji o tym, co robi i kiedy należy powyższe wezwanie. Przydatny byłby również bardziej konkretny przykład, taki jak struktura DbContext, gdzie można umieścić wyliczenia itp. –

+0

Wydaje się również brakować licencji i linku do kodu źródłowego, który może być problematyczny w przypadku niektórych projektów. –

+0

A w przypadku punktów bonusowych i tak nie mogę go uruchomić. Działa bez błędu, ale żadna tablica odnośników nie jest tworzona. –

1

mam włączone tę odpowiedź jako Zrobiłem kilka dodatkowych zmian od @HerrKater

zrobiłem mały dodatek do Herr Kater's Answer (również w oparciu o komentarzu Tim Abell'S). Aktualizacja polega na użyciu metody uzyskiwania wartości wyliczeniowej z atrybutu DisplayName, jeśli istnieje inny podział wartości wyliczenia 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 "); 
} 

Aktualizacja Herr Katers przykład wywołać metodę:

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

Enum Przykład

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

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

Oto pakiet Nuget zrobiłem wcześniej, że generuje tabele wyszukiwania i stosuje klucze obce i utrzymuje wiersze tabeli odnośników zsynchronizowane z wyliczeniem:

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

Dodaj to do swojego projektu i zadzwoń do metody Apply.

Dokumentacja na github: https://github.com/timabell/ef-enum-to-lookup

+7

Pure ** EF ** - wspaniały palec. Kropka. – Hallmanac

+2

Niesamowite, dziękuję. Chciałbym dać +10 – Andrey

+1

Serdecznie zapraszamy :-) –