EF5代码首先枚举和查找表
我想定义一个枚举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 }
我想为数据库生成创build一个表,如下所示:
create table UserType ( Id int, Name nvarchar(max) )
这可能吗?
这是不可能的。 EF支持与.NET相同级别的枚举,所以枚举值只是命名为integer =>类中的emum属性始终是数据库中的整数列。 如果你想拥有表格,那么你需要在你自己的数据库初始值设定器中手动创build它,连同外键在User
和填充枚举值。
我提出了一些关于用户语音的build议,以允许更复杂的映射。 如果您觉得有用,您可以投票支持该提案。
下面是我之前做的一个nuget包,它生成查找表并应用外键,并使查找表的行与enum保持同步:
https://www.nuget.org/packages/ef-enum-to-lookup
将其添加到您的项目并调用Apply方法。
github上的文档: https : //github.com/timabell/ef-enum-to-lookup
我写了一个辅助类,为UserEntities类中指定的枚举创build一个数据库表。 它还在引用枚举的表上创build一个外键。
所以这里是:
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); } } }
我已经为它创build了一个包
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作为你的种子function的一部分。 这将在sql server中为每个Enum创build表,并用正确的数据填充它。
我已经包含了这个答案,因为我从@HerrKater做了一些额外的修改
我对卡特先生的答案做了一个小小的补充(也是基于蒂姆·阿贝尔的评论)。 更新是使用一种方法从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(), "([az](?=[AZ])|[AZ](?=[AZ][az]))", "$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 }
你必须定制你的生成工作stream程
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