framework first enum code entity-framework ef-code-first entity-framework-5

entity framework - first - Primeros ENums y tablas de búsqueda del código EF5



entity framework code first enum table (6)

Aquí hay un paquete nuget que hice anteriormente que genera tablas de búsqueda y aplica claves externas, y mantiene las filas de la tabla de búsqueda sincronizadas con la enumeración:

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

Añádalo a su proyecto y llame al método Apply.

Documentación en github: https://github.com/timabell/ef-enum-to-lookup

Me gustaría definir una enumeración para EF5 y una tabla de búsqueda correspondiente. Sé que EF5 ahora admite enumeraciones, pero una vez listo, parece que solo admite esto en el nivel de objeto, y no agrega de manera predeterminada una tabla para estos valores de búsqueda.

Por ejemplo, tengo una entidad de usuario:

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

Y una enumeración UserType:

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

Me gustaría que la generación de la base de datos cree una tabla, algo así como:

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

es posible?


Escribí una pequeña clase de ayuda, que crea una tabla de base de datos para las enumeraciones especificadas en la clase UserEntities. También crea una clave foránea en las tablas que hacen referencia a la enumeración.

Asi que aqui esta:

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

usando el código:

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


He creado un paquete para él

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

Utilizar

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

"su contexto de objeto" - es su ensamblado EntityFramework DbContext "que contiene enumeraciones" - un ensamblaje que contiene sus enumeraciones

Llame a EnumTableGenerator.Run como parte de su función de inicialización. Esto creará tablas en el servidor SQL para cada Enum y lo poblará con datos correctos.


He incluido esta respuesta ya que he realizado algunos cambios adicionales desde @HerrKater

Hice una pequeña adición a Herr Kater''s Answer (también basada en el comentario de Tim Abell). La actualización consiste en utilizar un método para obtener el valor enum del atributo DisplayName, si existe, dividir el valor enum de 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 "); }

Actualice el ejemplo de Herr Katers para llamar al método:

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

Ejemplo de Enum

public enum PaymentMethod { [Display(Name = "Credit Card")] CreditCard = 1, [Display(Name = "Direct Debit")] DirectDebit = 2 }


No es directamente posible. EF admite enumeraciones en el mismo nivel que .NET, por lo que el valor enum se acaba de nombrar entero => propiedad enum en la clase siempre es una columna entera en la base de datos. Si también desea tener una tabla, debe crearla manualmente en su propio inicializador de base de datos junto con una clave externa en User y llenarla con valores enum.

Hice una propuesta sobre la voz del usuario para permitir mapeos más complejos. Si lo encuentra útil, puede votar por la propuesta.


debe personalizar su flujo de trabajo de generación

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