IT

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

lottoking 2020. 8. 10. 07:27
반응형

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


열거 형을 자동으로 생성 한 다음 데이터베이스 조회 테이블의 값을 기반으로 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");

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

그런 다음이 "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);

여기서 값은 정수 값 (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


우리가 잘못된 방향에서 오는 것입니까?

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

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

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


System.Web.Compilation.BuildProvider가 필요합니다.

나는 또한 구현하는 것이 의심 스럽지만, 내가 생각할 수없는 좋은 사용 사례가있을 수있다.

당신이 찾고있는 것은 빌드 공급자, 즉 System.Web.Compilation.BuildProvider입니다.

그들은 음속 에서 매우 효과적으로 사용되며 , 소스를 다운로드하고 그들이 어떻게 사용하는지 볼 수 있으며 , 그들이하는 일만큼 복잡한 것은 필요하지 않을 것입니다 .

도움이 되셨기를 바랍니다.


나는 항상 나만의 "사용자 정의 열거"를 작성하는 것을 좋아합니다. 좀 더 복잡한 클래스가 하나 추가 할 수 있습니다.

public abstract class CustomEnum
{
    private readonly string _name;
    private readonly object _id;

    protected CustomEnum( string name, object id )
    {
        _name = name;
        _id = id;
    }

    public string Name
    {
        get { return _name; }
    }

    public object Id
    {
        get { return _id; }
    }

    public override string ToString()
    {
        return _name;
    }
}

public abstract class CustomEnum<TEnumType, TIdType> : CustomEnum
    where TEnumType : CustomEnum<TEnumType, TIdType>
{
    protected CustomEnum( string name, TIdType id )
        : base( name, id )
    { }

    public new TIdType Id
    {
        get { return (TIdType)base.Id; }
    }

    public static TEnumType FromName( string name )
    {
        try
        {
            return FromDelegate( entry => entry.Name.Equals( name ) );
        }
        catch (ArgumentException ae)
        {
            throw new ArgumentException( "Illegal name for custom enum '" + typeof( TEnumType ).Name + "'", ae );
        }
    }

    public static TEnumType FromId( TIdType id )
    {
        try
        {
            return FromDelegate( entry => entry.Id.Equals( id ) );
        }
        catch (ArgumentException ae)
        {
            throw new ArgumentException( "Illegal id for custom enum '" + typeof( TEnumType ).Name + "'", ae );
        }
    }

    public static IEnumerable<TEnumType> GetAll()
    {
        var elements = new Collection<TEnumType>();
        var infoArray = typeof( TEnumType ).GetFields( BindingFlags.Public | BindingFlags.Static );

        foreach (var info in infoArray)
        {
            var type = info.GetValue( null ) as TEnumType;
            elements.Add( type );
        }

        return elements;
    }

    protected static TEnumType FromDelegate( Predicate<TEnumType> predicate )
    {
        if(predicate == null)
            throw new ArgumentNullException( "predicate" );

        foreach (var entry in GetAll())
        {
            if (predicate( entry ))
                return entry;
        }

        throw new ArgumentException( "Element not found while using predicate" );
    }
}

이제 사용하려는 열거 형을 비행합니다.

 public sealed class SampleEnum : CustomEnum<SampleEnum, int>
    {
        public static readonly SampleEnum Element1 = new SampleEnum( "Element1", 1, "foo" );
        public static readonly SampleEnum Element2 = new SampleEnum( "Element2", 2, "bar" );

        private SampleEnum( string name, int id, string additionalText )
            : base( name, id )
        {
            AdditionalText = additionalText;
        }

        public string AdditionalText { get; private set; }
    }

마침내 원하는대로 사용할 수 있습니다.

 static void Main( string[] args )
        {
            foreach (var element in SampleEnum.GetAll())
            {
                Console.WriteLine( "{0}: {1}", element, element.AdditionalText );
                Console.WriteLine( "Is 'Element2': {0}", element == SampleEnum.Element2 );
                Console.WriteLine();
            }

            Console.ReadKey();
        }

그리고 내 출력은 다음과 가변합니다.

Element1: foo
Is 'Element2': False

Element2: bar
Is 'Element2': True    

CodeSmith를 사용하여 다음과 같이 생성 할 수 있습니다.

http://www.csharping.com/PermaLink,guid,cef1b637-7d37-4691-8e49-138cbf1d51e9.aspx


나는 당신이 원하는 것을 좋은 방법이 있다고 생각합니다. 그리고 당신이 생각하는 생각이 당신이 원하는 생각 생각하지 않습니다.

동적 열거 형이 제공 참조 할 때 동적 값을해야 함을 의미합니다. 을 많이 사용 마법하면 이를 처리하고 DLL에 열거-type 파일을 생성하는 일종의 인텔리얻을 수 있습니다. 그러나 소요되는 작업량, IntelliSense 정보를 가져 오기 위해 데이터베이스에 액세스하는 것이 얼마나 비효율적 인 일지, 그리고 생성 된 DLL 파일을 제어하는 ​​버전의 악몽을 고려하십시오.

열거 형 값을 수동으로 추가하지 않고 추가해야 함 (어 · 든 데이터베이스에 추가해야 함) 대신 코드 도구 (예 : T4 템플릿)를 사용하십시오. 마우스 오른쪽 버튼을 클릭하고 실행하면 코드에서 열거 형을 정적으로 정의하고 열거 형 사용의 이점을 얻을 수 있습니다.


어떤 방식 으로든 동적 열거 형을 사용하는 것은 좋지 않습니다. 나중에 유지 관리하기 쉬운 명확하고 쉬운 코드를 보장 비용 데이터 "복제"문제를해야합니다.

자동 생성 라이브러리를 도입하기 시작하면 열거 형을 적절하게 클래스 개체 코딩하는 것보다 코드를 업그레이드해야하는 개발자에게 더 많은 혼란을 야기 할 것입니다.

주어진 다른 예제는 멋지고 흥미롭게 들리지만 코드 유지 관리에 대한 오버 헤드와 그로부터 그것에 대해 생각해 생각해. 또한 그 가치가 그렇게 자주 변경 될까요?


열거 형을 유지하고 동시에 값의 동적 목록을 만드는 한 가지 방법은 동적으로 나열된 사전과 함께 현재 가지고있는 열거 형을 사용하는 것입니다.

대부분의 열거 형은 사용하도록 정의 된 시나리오에서 사용하고 "동적 열거 형"은 동적 프로세스에서 지원 2를 구별 할 수 있습니다.

첫 번째 단계는 동적 항목에 대한 ID 및 참조를 포함하는 테이블 / 컬렉션을 만드는 것입니다. 표에서 가장 큰 Enum 값보다 훨씬 더 큰 자동 증가가 발생합니다.

이제 동적 Enum에 대한 부분이 나옵니다. 저는 Enum을 사용하여 규칙 집합을 적용하는 조건 집합을 만들 가정하고 일부는 동적으로 생성됩니다.

Get integer from database
If Integer is in Enum -> create Enum -> then run Enum parts
If Integer is not a Enum -> create Dictionary from Table -> then run Dictionary parts.

열거 형 빌더 클래스

public class XEnum
{
    private EnumBuilder enumBuilder;
    private int index;
    private AssemblyBuilder _ab;
    private AssemblyName _name;
    public XEnum(string enumname)
    {
        AppDomain currentDomain = AppDomain.CurrentDomain;
        _name = new AssemblyName("MyAssembly");
        _ab = currentDomain.DefineDynamicAssembly(
            _name, AssemblyBuilderAccess.RunAndSave);

        ModuleBuilder mb = _ab.DefineDynamicModule("MyModule");

        enumBuilder = mb.DefineEnum(enumname, TypeAttributes.Public, typeof(int));


    }
    /// <summary>
    /// adding one string to enum
    /// </summary>
    /// <param name="s"></param>
    /// <returns></returns>
    public FieldBuilder add(string s)
    {
        FieldBuilder f = enumBuilder.DefineLiteral(s, index);
        index++;
        return f;
    }
    /// <summary>
    /// adding array to enum
    /// </summary>
    /// <param name="s"></param>
    public void addRange(string[] s)
    {
        for (int i = 0; i < s.Length; i++)
        {
            enumBuilder.DefineLiteral(s[i], i);
        }
    }
    /// <summary>
    /// getting index 0
    /// </summary>
    /// <returns></returns>
    public object getEnum()
    {
        Type finished = enumBuilder.CreateType();
        _ab.Save(_name.Name + ".dll");
        Object o1 = Enum.Parse(finished, "0");
        return o1;
    }
    /// <summary>
    /// getting with index
    /// </summary>
    /// <param name="i"></param>
    /// <returns></returns>
    public object getEnum(int i)
    {
        Type finished = enumBuilder.CreateType();
        _ab.Save(_name.Name + ".dll");
        Object o1 = Enum.Parse(finished, i.ToString());
        return o1;
    }
}

개체 만들기

string[] types = { "String", "Boolean", "Int32", "Enum", "Point", "Thickness", "long", "float" };
XEnum xe = new XEnum("Enum");
        xe.addRange(types);
        return xe.getEnum();

참고 URL : https://stackoverflow.com/questions/725043/automatically-create-an-enum-based-on-values-in-a-database-lookup-table

반응형