EF5 Code First Enumeraciones y Tablas de Búsqueda


Me gustaría definir una enumeración para EF5 y una tabla de búsqueda correspondiente. Sé que EF5 ahora admite enumeraciones, pero fuera de la caja, parece que solo admite esto a nivel de objeto, y no agrega una tabla por defecto 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 un enum UserType:

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

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

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

Es esto posible?

Author: Jerad Rose, 2012-06-23

6 answers

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

Hice una propuesta sobre user voice para permitir asignaciones más complejas. Si le resulta útil, puede votar a favor de la propuesta.

 15
Author: Ladislav Mrnka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-02 08:21:59

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

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

Agregue eso a su proyecto y llame al método Apply.

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

 20
Author: Tim Abell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-01 15:17:39

Escribí una pequeña clase helper, 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.

Así que aquí está:

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

}
 8
Author: Herr Kater,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-25 11:01:17

He creado un paquete para ello

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

Use

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

"su contexto de objeto" - es su EntityFramework DbContext "asamblea que contiene enumeraciones" - una asamblea que contiene sus enumeraciones

Llama a EnumTableGenerator.Ejecutar como parte de su función seed. Esto creará tablas en sql server para cada enumeración y las rellenará con los datos correctos.

 1
Author: fenix2222,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-14 03:36:52

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

Hice una pequeña adición a La respuesta de Herr Kater (también basada en el comentario de Tim Abell). La actualización es usar un método para obtener el valor de enumeración del atributo DisplayName si existe, de lo contrario dividir el valor de enumeración 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 enumeración

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

    [Display(Name = "Direct Debit")]
    DirectDebit = 2
}
 1
Author: 12c4IT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:31:07

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
 -3
Author: Aghilas Yakoub,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-23 08:29:53