如何根据数据库查找表中的值(使用企业库数据层)自动创建枚举并随后在C#中使用其值?
例如,如果我在数据库中添加一个新的查找值,我不想在代码中手动添加额外的静态枚举值声明 - 我想让枚举与数据库保持同步.
有这样的事吗?
我不想创建代码生成的静态枚举(根据代码项目文章枚举代码生成器 - 从数据库查找表自动生成枚举代码),并希望它是完全自动的.
我正在做这件事,但你需要做一些代码生成才能实现.
在我的解决方案中,我添加了一个项目"EnumeratedTypes".这是一个控制台应用程序,它从数据库中获取所有值并从中构造枚举.然后它将所有枚举保存到程序集中.
枚举生成代码是这样的:
// 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 name = new AssemblyName("MyEnums"); AssemblyBuilder assemblyBuilder = currentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave); // Define a dynamic module in "MyEnums" assembly. // For a single-module assembly, the module has the same name as the assembly. ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(name.Name, name.Name + ".dll"); // Define a public enumeration with the name "MyEnum" and an underlying type of Integer. EnumBuilder myEnum = moduleBuilder.DefineEnum("EnumeratedTypes.MyEnum", TypeAttributes.Public, typeof(int)); // Get data from database MyDataAdapter someAdapter = new MyDataAdapter(); MyDataSet.MyDataTable myData = myDataAdapter.GetMyData(); foreach (MyDataSet.MyDataRow row in myData.Rows) { myEnum.DefineLiteral(row.Name, row.Key); } // Create the enum myEnum.CreateType(); // Finally, save the assembly assemblyBuilder.Save(name.Name + ".dll");
我在解决方案中的其他项目引用此生成的程序集.结果,我可以在代码中使用动态枚举,并使用intellisense.
然后,我添加了一个构建后事件,以便在构建此"EnumeratedTypes"项目之后,它会自行运行并生成"MyEnums.dll"文件.
顺便说一句,它有助于更改项目的构建顺序,以便首先构建"EnumeratedTypes".否则,一旦开始使用动态生成的.dll,如果.dll被删除,您将无法进行构建.(鸡和鸡蛋的问题 - 解决方案中的其他项目需要这个.dll才能正确构建,并且在构建解决方案之前无法创建.dll ...)
我从这篇msdn文章中得到了上面的大部分代码.
希望这可以帮助!
枚举必须在编译时指定,你不能在运行时动态添加枚举 - 为什么你会在代码中没有使用/引用它们?
来自Professional C#2008:
C#中枚举的真正强大之处在于它们在幕后实例化为从基类System.Enum派生的结构.这意味着可以调用针对它们的方法来执行一些有用的任务.请注意,由于.NET Framework的实现方式,在语法上将枚举视为结构时,不存在性能损失.在实践中,一旦编译了代码,枚举将作为基本类型存在,就像int和float一样.
所以,我不确定你能以你想要的方式使用Enums.
它必须是一个真正的枚举?用一个Dictionary
代替怎么样?
例如
DictionaryMyEnum = new Dictionary(){{"One", 1}, {"Two", 2}}; Console.WriteLine(MyEnum["One"]);
我用T4模板完成了这个.将.tt文件放入项目并设置Visual Studio以将T4模板作为预构建步骤运行是相当简单的.
T4生成.cs文件,这意味着您只需查询数据库并从结果中在.cs文件中构建枚举.作为预构建任务接线,它会在每次构建时重新创建枚举,或者您可以根据需要手动运行T4.
假设您的数据库中包含以下内容:
table enums ----------------- | id | name | ----------------- | 0 | MyEnum | | 1 | YourEnum | ----------------- table enum_values ---------------------------------- | id | enums_id | value | key | ---------------------------------- | 0 | 0 | 0 | Apple | | 1 | 0 | 1 | Banana | | 2 | 0 | 2 | Pear | | 3 | 0 | 3 | Cherry | | 4 | 1 | 0 | Red | | 5 | 1 | 1 | Green | | 6 | 1 | 2 | Yellow | ----------------------------------
构造一个select以获取所需的值:
select * from enums e inner join enum_values ev on ev.enums_id=e.id where e.id=0
构造枚举的源代码,你会得到类似的东西:
String enumSourceCode = "enum " + enumName + "{" + enumKey1 + "=" enumValue1 + "," + enumKey2 + ... + "}";
(显然这是在某种循环中构建的.)
然后是有趣的部分,编译你的枚举并使用它:
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp"); CompilerParameters cs = new CompilerParameters(); cp.GenerateInMemory = True; CompilerResult result = provider.CompileAssemblyFromSource(cp, enumSourceCode); Type enumType = result.CompiledAssembly.GetType(enumName);
现在您已经编译并准备好使用了.
要获取存储在DB中的枚举值,您可以使用:
[Enum].Parse(enumType, value);
其中value可以是整数值(0,1,等)或枚举文本/键(Apple,Banana等)
只是用"货架"代码和一些解释来展示Pandincus 的 答案:你需要两个解决方案用于这个例子(我知道它也可以通过一个来完成;),让高级学生介绍它......
所以这是表的DDL SQL:
USE [ocms_dev] GO CREATE TABLE [dbo].[Role]( [RoleId] [int] IDENTITY(1,1) NOT NULL, [RoleName] [varchar](50) NULL ) ON [PRIMARY]
所以这是生成dll的控制台程序:
using System; using System.Collections.Generic; using System.Text; using System.Reflection; using System.Reflection.Emit; using System.Data.Common; using System.Data; using System.Data.SqlClient; namespace DynamicEnums { class EnumCreator { // after running for first time rename this method to Main1 static void Main () { string strAssemblyName = "MyEnums"; bool flagFileExists = System.IO.File.Exists ( AppDomain.CurrentDomain.SetupInformation.ApplicationBase + strAssemblyName + ".dll" ); // 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 name = new AssemblyName ( strAssemblyName ); AssemblyBuilder assemblyBuilder = currentDomain.DefineDynamicAssembly ( name, AssemblyBuilderAccess.RunAndSave ); // Define a dynamic module in "MyEnums" assembly. // For a single-module assembly, the module has the same name as // the assembly. ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule ( name.Name, name.Name + ".dll" ); // Define a public enumeration with the name "MyEnum" and // an underlying type of Integer. EnumBuilder myEnum = moduleBuilder.DefineEnum ( "EnumeratedTypes.MyEnum", TypeAttributes.Public, typeof ( int ) ); #region GetTheDataFromTheDatabase DataTable tableData = new DataTable ( "enumSourceDataTable" ); string connectionString = "Integrated Security=SSPI;Persist " + "Security Info=False;Initial Catalog=ocms_dev;Data " + "Source=ysg"; using (SqlConnection connection = new SqlConnection ( connectionString )) { SqlCommand command = connection.CreateCommand (); command.CommandText = string.Format ( "SELECT [RoleId], " + "[RoleName] FROM [ocms_dev].[dbo].[Role]" ); Console.WriteLine ( "command.CommandText is " + command.CommandText ); connection.Open (); tableData.Load ( command.ExecuteReader ( CommandBehavior.CloseConnection ) ); } //eof using foreach (DataRow dr in tableData.Rows) { myEnum.DefineLiteral ( dr[1].ToString (), Convert.ToInt32 ( dr[0].ToString () ) ); } #endregion GetTheDataFromTheDatabase // Create the enum myEnum.CreateType (); // Finally, save the assembly assemblyBuilder.Save ( name.Name + ".dll" ); } //eof Main } //eof Program } //eof namespace
这是Console编程打印输出(记住它必须引用dll).让高级学生提出解决方案,将一个解决方案中的所有内容与动态加载相结合,并检查是否已经构建了dll.
// add the reference to the newly generated dll use MyEnums ; class Program { static void Main () { Array values = Enum.GetValues ( typeof ( EnumeratedTypes.MyEnum ) ); foreach (EnumeratedTypes.MyEnum val in values) { Console.WriteLine ( String.Format ( "{0}: {1}", Enum.GetName ( typeof ( EnumeratedTypes.MyEnum ), val ), val ) ); } Console.WriteLine ( "Hit enter to exit " ); Console.ReadLine (); } //eof Main } //eof Program