Entity framework 实体框架5-从数据库中存储的值动态生成枚举

Entity framework 实体框架5-从数据库中存储的值动态生成枚举,entity-framework,ef-code-first,enumeration,Entity Framework,Ef Code First,Enumeration,因此,我的数据库中有一个现有的查找表,它存储一个ID列(int),ID值的描述/名称。我们一直在使用此表中的数据进行枚举。 此后,我们开始使用EntityFramework5和CodeFirst,但我们的查找值仍在数据库中。我们想要做的是创建一个实体来表示值,最好是一个枚举来访问该表中的值和名称,并使它们在我们的应用程序中可用 通常,下面的代码对于从数据库值动态构建枚举类型是有意义的,但我们不想这样做 static void GenerateStateEnumerations(String

因此,我的数据库中有一个现有的查找表,它存储一个ID列(int),ID值的描述/名称。我们一直在使用此表中的数据进行枚举。

此后,我们开始使用EntityFramework5和CodeFirst,但我们的查找值仍在数据库中。我们想要做的是创建一个实体来表示值,最好是一个枚举来访问该表中的值和名称,并使它们在我们的应用程序中可用

通常,下面的代码对于从数据库值动态构建枚举类型是有意义的,但我们不想这样做

 static void GenerateStateEnumerations(String enumassemblyName, String enumTypeName, String assemblyName, IDictionary<int, String> EnumDB)
    {
        // Get the current application domain for the current thread.
        AppDomain currentDomain = AppDomain.CurrentDomain;
         // Create a dynamic assembly in the current application domain,  
         // and allow it to be executed and saved to disk.
        AssemblyName EnumassemblyName = new AssemblyName(enumassemblyName);

         AssemblyBuilder ab = currentDomain.DefineDynamicAssembly(
        EnumassemblyName, AssemblyBuilderAccess.RunAndSave);
        // Define a dynamic module in assemblyName assembly. For a single-
        // module assembly, the module has the same name as the assembly.
         ModuleBuilder mb = ab.DefineDynamicModule(EnumassemblyName.Name, EnumassemblyName.Name + ".dll");
         // Define a public enumeration with the name "Elevation" and an 
         // underlying type of Integer.
         EnumBuilder eb = mb.DefineEnum(enumTypeName, TypeAttributes.Public, typeof(int));
        // Define the enumeration members
         foreach (KeyValuePair<int, String> element in EnumDB)
         {
             eb.DefineLiteral(element.Value, element.Key);
         }
         // Create the type and save the assembly.
         Type finished = eb.CreateType();
        //Save the assembly via the assembly builder
         ab.Save(EnumassemblyName.Name + ".dll");
    }
static void generateStateNumerations(字符串enumassemblyName、字符串enumTypeName、字符串assemblyName、IDictionary EnumDB)
{
//获取当前线程的当前应用程序域。
AppDomain currentDomain=AppDomain.currentDomain;
//在当前应用程序域中创建动态程序集,
//并允许将其执行并保存到磁盘。
AssemblyName EnumassemblyName=新的AssemblyName(EnumassemblyName);
AssemblyBuilder ab=currentDomain.DefinedDynamicAssembly(
EnumassemblyName、AssemblyBuilderAccess.RunAndSave);
//在assemblyName assembly中定义动态模块。对于单个-
//模块程序集,模块与程序集具有相同的名称。
ModuleBuilder mb=ab.DefinedDynamicModule(EnumassemblyName.Name,EnumassemblyName.Name+“.dll”);
//定义一个名为“高程”的公共枚举和
//整数的基础类型。
EnumBuilder eb=mb.DefineEnum(enumTypeName,TypeAttributes.Public,typeof(int));
//定义枚举成员
foreach(EnumDB中的KeyValuePair元素)
{
eb.DefineLiteral(element.Value,element.Key);
}
//创建类型并保存程序集。
类型finished=eb.CreateType();
//通过部件生成器保存部件
ab.Save(EnumassemblyName.Name+“.dll”);
}

在EF 5中,如何创建一个枚举实体来表示存储在此表中的数据?目前是否可能

我知道您说过不想动态执行此操作,但您是否考虑过使用文本模板?如果使用文本模板(*.tt T4文件),则每次生成时都会动态生成枚举。表中的任何新值都将自动添加到代码中的枚举中

下面是一个如何从文本模板创建枚举的示例:

<#@ template language="C#" hostSpecific="true" #>
<#@ output extension=".generated.cs" #>
<#@ Assembly Name="C:\Program Files (x86)\Common Files\microsoft shared\MSEnv\PublicAssemblies\EnvDTE.dll" #>
<#@ Assembly Name="System.Data" #>
<#@ assembly name="System.Configuration.dll" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Configuration" #>
<#@ import namespace="System.Data" #>
<#@ import namespace="System.Data.SqlClient" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#
// This file dynamically creates Enumerations to be used in the [your project name] project.
// get an appSetting value
//string myAppSetting = AppSettings["myAppSetting"].Value;
// use a helper method to get value or default
// string absentAppSetting = (string)AppSettingValueOrDefault("xxx","default value for absent setting");
// get a project property
//string rootNamespace = Project.Properties.Item("RootNamespace").Value.ToString();

ConnectionStringSettings cs = ConnectionStrings["MyDBName"];

string tableName = "dbo.MyEnumTable"; // Path.GetFileNameWithoutExtension(Host.TemplateFile);
string path = Path.GetDirectoryName(Host.TemplateFile);
string columnId = "MyEnumTableId"; 
string columnName = "MyEnumTableValue"; 
string connectionString = cs.ConnectionString;

// Get containing project

IServiceProvider serviceProvider = (IServiceProvider)Host;
DTE dte = (DTE)serviceProvider.GetService(typeof(DTE));
Project project = dte.Solution.FindProjectItem(Host.TemplateFile).ContainingProject;
 # > //remove space between # > issue with SO formatting

using System;
using System.CodeDom.Compiler; 
using System.Collections.Generic;

namespace <#= project.Properties.Item("DefaultNamespace").Value #>
{
/// <summary>
/// Auto generated enumeration from database table <#= tableName #>
/// </summary>

[GeneratedCode("TextTemplatingFileGenerator", "10")]
public enum MyEnumTableEnum
{
<#

SqlConnection conn = new SqlConnection(connectionString);
string command = string.Empty;

command = string.Format("select tbl.{0}, tbl.{1} from {2} as tbl order by tbl.{0}", columnId, columnName, tableName);

SqlCommand comm = new SqlCommand(command, conn);

conn.Open();

SqlDataReader reader = comm.ExecuteReader();
bool loop = reader.Read();

while(loop)
{
# >  //remove space between # > issue with SO formatting      
/// <summary>
    /// <#= reader[columnName] #> configuration setting. 
    /// </summary>
    <#= Pascalize(reader[columnName]) #> = <#= reader[columnId] #><# loop = reader.Read(); #><#= loop ? ",\r\n" : string.Empty #>
<#
}
#>  


}

/// <summary>
/// This auto generated class is used to get or set the MyEnumTableEnum user friendly display names.
/// The 'values' object is of type Dictionary<int, string>
/// Usage: string keyValue = MyEnumTableDict.values[int key];
/// </summary>
public class MyEnumTableDict
{
    public static Dictionary<int, string> values = new Dictionary<int, string>();

    static MyEnumTableDict()
    {
        <#
            reader.Close();
            reader = comm.ExecuteReader();
            loop = reader.Read();

while(loop)
{
#>
        values[<#= reader[columnId] #>] = "<#= reader[columnName] #>";<#= "\r\n" #><# loop = reader.Read(); #>
<#
}
reader.Close();
reader.Dispose();
#>
    }       
}

}

<#+
/// <summary>
/// Used to Pascal-case objects
/// </summary>
private string Pascalize(object value)
{
    Regex rx = new Regex(@"(?:[^a-zA-Z0-9]*)(?<first>[a-zA-Z0-9])(?<reminder>[a-zA-Z0-9]*)(?:[^a-zA-Z0-9]*)");
    return rx.Replace(value.ToString(), m => m.Groups["first"].ToString().ToUpper() + m.Groups["reminder"].ToString().ToLower());
}

// Configuration Accessor Helpers

private static System.Configuration.Configuration _config;
private static EnvDTE.Project _project;

/// <summary>
/// Example:
/// <code>
/// string cs = ConnectionStrings["myConnectionString"].ConnectionString;
/// </code>
/// </summary>
private ConnectionStringSettingsCollection ConnectionStrings
{
   get { return Configuration.ConnectionStrings.ConnectionStrings;}
}

/// <summary>
/// Example:
/// <code>
/// string setting = AppSettings["mySetting"].Value;
/// </code>
/// </summary>
private KeyValueConfigurationCollection AppSettings
{
   get { return Configuration.AppSettings.Settings; }
}

/// <summary>
/// Returns value of setting, if present, otherwise defaultValue
/// </summary>
/// <param name="key">appSettings key</param>
/// <param name="defaultValue">value to return if setting is absent</param>
/// <returns></returns>
private object AppSettingValueOrDefault(string key,object defaultValue)
{
   if (AppSettings[key] != null)
   {
        return AppSettings[key].Value;
   }          

   return defaultValue;
}


/// <summary>
/// The app/web config file for hosting project, if any
/// </summary>
private System.Configuration.Configuration Configuration
{
    get
    {
        if(_config==null)
        {
            string configurationFilename=null;  

            // examine each project item's filename looking for app.config or web.config
            foreach (EnvDTE.ProjectItem item in Project.ProjectItems)
            {
                if (Regex.IsMatch(item.Name,"(app|web).config",RegexOptions.IgnoreCase))
                {
                    // TODO: try this with linked files. is the filename pointing to the source?
                    configurationFilename=item.get_FileNames(0);
                    break;
                }
            }

            if(!string.IsNullOrEmpty(configurationFilename))
            {
                // found it, map it and return it
                ExeConfigurationFileMap configFile = null;
                configFile = new ExeConfigurationFileMap();
                configFile.ExeConfigFilename=configurationFilename;

                _config = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(configFile, ConfigurationUserLevel.None);
            }  
        }

        return _config;
    }
}

/// <summary>
/// The hosting project.
/// </summary>
private EnvDTE.Project Project
{
    get
    {
        if(_project==null)
        {
            // Get the instance of Visual Studio that is hosting the calling file
            EnvDTE.DTE env = (EnvDTE.DTE)((IServiceProvider)this.Host).GetService(typeof(EnvDTE.DTE));
            // Gets an array of currently selected projects. Since you are either in this file saving it or
            // right-clicking the item in solution explorer to invoke the context menu it stands to reason
            // that there is 1 ActiveSolutionProject and that it is the parent of this file....
            _project = (EnvDTE.Project)((Array)env.ActiveSolutionProjects).GetValue(0);
        }

        return _project;
    }
}

#>
更新:

忘记包含输出类。现在包括完整性:)

使用系统;
使用System.CodeDom.Compiler;
使用System.Collections.Generic;
名称空间MyNameSpace
{
/// 
///从数据库表dbo.MyEnumTable自动生成枚举
/// 
[生成代码(“TextTemplatingFileGenerator”,“10”)]
公共枚举MyEnumTableDictEnum
{
/// 
///说明1
/// 
enumName1=1,
/// 
///说明2
/// 
enumName2=2,
//……等等。
}
/// 
///此自动生成的类用于获取或设置MyEnumTableDictEnum
///用户友好的显示名称。
///“values”对象的类型为Dictionary
///用法:string keyValue=MyEnumTableDict.values[int key];
/// 
公共类MyEnumTableDict
{
公共静态字典值=新字典();
静态MyEnumTableDict()
{
值[1]=“EnumName1”;
值[2]=“EnumName2”;
值[3]=“…等”;
}       
}
}

您是否需要一个表示表的实体(即带有键和描述),或者您只需要在任何地方都使用的枚举类型,因此您的模型中甚至不需要该表的实体?枚举是否会发生变化?您是否使用数据库优先的方法?
using System;
using System.CodeDom.Compiler; 
using System.Collections.Generic;

namespace MyNameSpace
{
    /// <summary>
    /// Auto generated enumeration from database table dbo.MyEnumTable
    /// </summary>

    [GeneratedCode("TextTemplatingFileGenerator", "10")]
    public enum MyEnumTableDictEnum
    {
        /// <summary>
        /// description 1
        /// </summary>
        enumName1 = 1,

        /// <summary>
        /// description 2 
        /// </summary>
        enumName2 = 2,

        //..etc.
     }

    /// <summary>
    /// This auto generated class is used to get or set the MyEnumTableDictEnum 
    ///   user friendly display names.
    /// The 'values' object is of type Dictionary<int, string>
    /// Usage: string keyValue = MyEnumTableDict.values[int key];
    /// </summary>
    public class MyEnumTableDict
    {
        public static Dictionary<int, string> values = new Dictionary<int, string>();

        static MyEnumTableDict()
        {
                    values[1] = "EnumName1";
            values[2] = "EnumName2";
            values[3] = "...etc.";

        }       
     }
}