当前位置:  开发笔记 > 编程语言 > 正文

根据数据库查找表中的值自动创建枚举?

如何解决《根据数据库查找表中的值自动创建枚举?》经验,为你挑选了6个好方法。

如何根据数据库查找表中的值(使用企业库数据层)自动创建枚举并随后在C#中使用其值?

例如,如果我在数据库中添加一个新的查找值,我不想在代码中手动添加额外的静态枚举值声明 - 我想让枚举与数据库保持同步.

有这样的事吗?


我不想创建代码生成的静态枚举(根据代码项目文章枚举代​​码生成器 - 从数据库查找表自动生成枚举代码),并希望它是完全自动的.



1> Pandincus..:

我正在做这件事,但你需要做一些代码生成才能实现.

在我的解决方案中,我添加了一个项目"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文章中得到了上面的大部分代码.

希望这可以帮助!


对于那些不知道如何在post-build上运行生成的可执行文件的人:1)右键单击项目2)单击属性3)单击Build Events 4)在"Post-build event command lines"文本框中输入$(TARGETPATH)

2> Marcus L..:

枚举必须在编译时指定,你不能在运行时动态添加枚举 - 为什么你会在代码中没有使用/引用它们?

来自Professional C#2008:

C#中枚举的真正强大之处在于它们在幕后实例化为从基类System.Enum派生的结构.这意味着可以调用针对它们的方法来执行一些有用的任务.请注意,由于.NET Framework的实现方式,在语法上将枚举视为结构时,不存在性能损失.在实践中,一旦编译了代码,枚举将作为基本类型存在,就像int和float一样.

所以,我不确定你能以你想要的方式使用Enums.


海报和18名赞成有点错过了他的观点.听起来他想要*生成*枚举,而不是运行时动态枚举.
@Oliver如果你想论证语义,是的,你是对的.但我同意Graphain的评论 - 我相信OP正在寻找_generated_ enums.他希望枚举值来自数据库而不必硬编码.

3> Autodidact..:

它必须是一个真正的枚举?用一个Dictionary代替怎么样?

例如

Dictionary MyEnum = new Dictionary(){{"One", 1}, {"Two", 2}};
Console.WriteLine(MyEnum["One"]);


我不会这样做.您失去了编译时间检查并且容易出现输入错误.枚举的所有好处都消失了.你可以引入字符串常量,但是你回到了你开始的地方.
+1.使用字典或HashSet最接近动态枚举.完全动态意味着它在运行时发生,因此必须在运行时进行错误检查.

4> CodingWithSp..:

我用T4模板完成了这个.将.tt文件放入项目并设置Visual Studio以将T4模板作为预构建步骤运行是相当简单的.

T4生成.cs文件,这意味着您只需查询数据库并从结果中在.cs文件中构建枚举.作为预构建任务接线,它会在每次构建时重新创建枚举,或者您可以根据需要手动运行T4.



5> Sani Singh H..:

假设您的数据库中包含以下内容:

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等)


这会以什么方式实际帮助?没有类型安全,也没有智能感知.基本上它只是一种使用常量的更复杂的方式,因为他无论如何都必须提供值.
萨尼 - 完美!这正是我所需要的.对于那些质疑这样的原因的人,我使用的是供应商库,需要将属性设置为枚举的名称.枚举限制同一对象的不同属性的有效值范围.在我的情况下,我正在加载元数据,包括数据库中的有效值范围; 不,供应商代码不支持将任何类型的集合传递给属性.谢谢

6> Yordan Georg..:

只是用"货架"代码和一些解释来展示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

推荐阅读
手机用户2502851955
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有