[c#] 데이터베이스 조회 테이블의 값을 기반으로 Enum을 자동으로 생성 하시겠습니까?

열거 형을 자동으로 생성 한 다음 데이터베이스 조회 테이블의 값을 기반으로 C #에서 해당 값을 사용하는 방법 (엔터프라이즈 라이브러리 데이터 레이어 사용)?

예를 들어, 데이터베이스에 새 조회 값을 추가하는 경우 코드에 추가 정적 열거 형 값 선언을 수동으로 추가 할 필요가 없습니다. 열거 형을 데이터베이스와 동기화 상태로 유지하고 싶습니다.

이것과 같은 것이 있습니까?


코드 생성 정적 열거 형 ( 코드 프로젝트 기사 Enum Code Generator-Generating enum code automatically from database look up tables에 따라 )을 생성하고 싶지 않으며 완전히 자동 인 것을 선호합니다.



답변

나는이 정확한 일을하고 있어요,하지만 당신은 해야 할 일이에 대한 코드 생성의 어떤 종류의 일을 할 수 있습니다.

내 솔루션에서 “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");

솔루션의 다른 프로젝트는이 생성 된 어셈블리를 참조합니다. 결과적으로 코드에서 인텔리 센스로 완성 된 동적 열거 형을 사용할 수 있습니다.

그런 다음이 “EnumeratedTypes”프로젝트가 빌드 된 후 자체적으로 실행되고 “MyEnums.dll”파일을 생성하도록 빌드 후 이벤트를 추가했습니다.

그건 그렇고, “EnumeratedTypes”가 먼저 빌드되도록 프로젝트 의 빌드 순서 를 변경하는 데 도움이됩니다 . 그렇지 않으면 동적으로 생성 된 .dll을 사용하기 시작하면 .dll이 삭제되면 빌드를 수행 할 수 없습니다. (닭고기와 달걀 종류의 문제-솔루션의 다른 프로젝트에서 제대로 빌드하려면이 .dll이 필요하며 솔루션을 빌드 할 때까지 .dll을 만들 수 없습니다 …)

이 msdn 기사 에서 위의 코드 대부분을 얻었습니다 .

도움이 되었기를 바랍니다!


답변

열거 형은 컴파일 타임에 지정해야합니다. 런타임 동안에는 열거 형을 동적으로 추가 할 수 없습니다. 왜 코드에서 열거 형에 대한 사용 / 참조가 없을까요?

Professional C # 2008에서 :

C #에서 열거 형의 진정한 힘은 배후에서 기본 클래스 인 System.Enum에서 파생 된 구조체로 인스턴스화된다는 것입니다. 이것은 유용한 작업을 수행하기 위해 그들에 대해 메서드를 호출 할 수 있음을 의미합니다. .NET Framework가 구현되는 방식으로 인해 열거 형을 구문 적으로 구조체로 처리하는 것과 관련된 성능 손실은 없습니다. 실제로 코드가 컴파일되면 enum은 int 및 float처럼 기본 유형으로 존재합니다.

따라서 원하는 방식으로 Enum을 사용할 수 있는지 잘 모르겠습니다.


답변

실제 열거 형이어야합니까? Dictionary<string,int>대신 사용하는 것은 어떻습니까?

예를 들면

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


답변

T4 템플릿 으로이 작업을 수행했습니다 . .tt 파일을 프로젝트에 드롭하고 빌드 전 단계로 T4 템플릿을 실행하도록 Visual Studio를 설정하는 것은 매우 간단합니다.

T4는 .cs 파일을 생성하므로 데이터베이스를 쿼리하고 결과에서 .cs 파일에 열거 형을 만들 수 있습니다. 빌드 전 작업으로 연결되어 모든 빌드에서 열거 형을 다시 생성하거나 필요에 따라 T4를 수동으로 실행할 수 있습니다.


답변

DB에 다음이 있다고 가정 해 보겠습니다.

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 * 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 값을 얻으려면 다음을 사용할 수 있습니다.

[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 

다음은 출력을 인쇄하는 콘솔 프로그래밍입니다 (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


답변

우리가 잘못된 방향에서 오는 것 아닌가요?

배포 된 릴리스의 수명 동안 데이터가 전혀 변경 될 가능성이있는 경우 열거 형은 적절하지 않으며 사전, 해시 또는 기타 동적 컬렉션을 사용해야합니다.

배포 된 릴리스의 수명 동안 가능한 값 집합이 고정되어 있음을 알고있는 경우 열거 형을 사용하는 것이 좋습니다.

당신이 경우 해야한다 열거 세트를 복제 데이터베이스에 뭔가를 가지고, 왜 지우고 열거 값의 최종 세트로 데이터베이스 테이블을 다시 채울 수있는 배포 단계를 추가하지?