32

我想定义一个供 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)
)

这可能吗?

4

6 回答 6

22

这是我之前制作的一个 nuget 包,它生成查找表并应用外键,并使查找表行与枚举保持同步:

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

将其添加到您的项目并调用 Apply 方法。

github 上的文档:https ://github.com/timabell/ef-enum-to-lookup

于 2014-10-23T12:41:47.100 回答
18

这不是直接可能的。EF 支持与 .NET 相同级别的枚举,因此枚举值仅命名为整数 => 类中的枚举属性始终是数据库中的整数列。如果您还想拥有表,则需要在您自己的数据库初始化程序中手动创建它以及外键,User并用枚举值填充它。

我提出了一些关于用户语音的建议,以允许更复杂的映射。如果您觉得它有用,您可以为该提案投票。

于 2012-06-23T22:36:27.173 回答
9

我写了一个小助手类,它为 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);
        }
    }

}
于 2013-02-25T11:01:17.203 回答
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 创建表,并用正确的数据填充它。

于 2014-05-09T02:34:29.857 回答
1

我已经包含了这个答案,因为我从@HerrKater 做了一些额外的改变

我对Herr Kater 的回答做了一点补充(也是基于 Tim Abell 的评论)。更新是使用一种方法从 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 ");
 }

更新 Herr 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
}
于 2014-10-10T00:03:33.643 回答
-3

您必须自定义您的生成工作流程

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
于 2012-06-23T08:29:53.093 回答