【问题标题】:Automatically create an Enum based on values in a database lookup table?根据数据库查找表中的值自动创建枚举?
【发布时间】:2021-11-25 17:45:56
【问题描述】:

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

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

有这样的事情吗?


我不想创建代码生成的静态枚举(根据 The Code Project 文章 Enum Code Generator - Generating enum code automatically from database look up tables)并且希望它是完全自动的。

【问题讨论】:

  • 您是否有可能尝试以有更好解决方案的方式使用枚举?
  • 我支持@Dan,必须有更好的方法来做到这一点。
  • @mydogisbox 更好的方法是什么?
  • @eranotzer 实际上,在考虑了一下之后,编写一个查询数据库并从中生成枚举的预构建步骤会非常简单
  • 话虽如此,我不确定他所说的“我不想创建代码生成的静态枚举”是什么意思,所以也许这不符合需要。

标签: c# database dynamic enums


【解决方案1】:

我正在做这件事,但您需要生成某种代码才能使其正常工作。

在我的解决方案中,我添加了一个项目“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...)

我从this msdn article获得了上述大部分代码。

希望这会有所帮助!

【讨论】:

  • 对于那些不知道如何在构建后运行生成的可执行文件的人:1)右键单击项目 2)单击属性 3)单击构建事件 4)在“后-构建事件命令行”文本框类型 $(TargetPath)
【解决方案2】:

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

来自 Professional C# 2008:

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

所以,我不确定您是否可以按照自己的方式使用枚举。

【讨论】:

  • 不确定 billfredtom 的推理是什么,但我认为我可以避免对某些键进行手动字符串查找,而是将它们内置到我的代码中。我只是更喜欢能够对强类型值而不是弱字符串执行逻辑。需要注意的是,由于我们现在有依赖于动态生成的 Enum 的代码,如果我们从数据库中删除该值,下次我们尝试编译代码时它将失败。
  • 海报和 18 次投票有点错过了他的观点。听起来他想要生成的枚举,而不是运行时动态枚举。
  • +1。枚举基本上只是定义整数常量的另一种方式(即使System.Enum 有一些附加功能)。而不是写const int Red=0, Green=1, Blue=3; 你写enum { Red, Green, Blue }。常量根据定义是常量而不是动态的。
  • @Oliver 如果你想争论语义,是的,你是对的。但我同意 Graphain 的评论——我相信 OP 正在寻找 generated 枚举。他希望枚举值来自数据库,而不必对它们进行硬编码。
  • 或者...假设我允许我的 web.config 中的某个人为我的电子邮件模板代码定义电子邮件模板的令牌类型。如果我现有的表示这些字符串类型的名为 EmailTokens 的枚举将基于我的 web.config 中定义的那些类型生成,那就太好了。因此,如果有人通过我的键值在 webconfig 中添加新的电子邮件令牌,例如“电子邮件,FName”,我已经有一个枚举,我将用它来表示这些令牌,例如 EmailTemplate.Email会自动添加 const
【解决方案3】:

它必须是一个实际的枚举吗?改用Dictionary<string,int> 怎么样?

例如

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

【讨论】:

  • 我不会尝试这样做。您放松了编译时检查,并且容易出现输入错误。枚举的所有好处都消失了。你可以引入字符串常量,但是你又回到了你开始的地方。
  • 我同意。但请记住,错误输入的字符串将在运行时被捕获。只需添加一个测试用例即可覆盖所有枚举成员。
  • 如果您使用常量而不是文字,输入错误不是问题
  • +1。使用字典或 HashSet 最接近动态枚举。完全动态意味着它发生在运行时,因此必须在运行时进行错误检查。
  • 这是一个很好的答案,比起在启动时编译 dll 更愿意这样做
【解决方案4】:

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

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

【讨论】:

    【解决方案5】:

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

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

    现在您已编译并准备好使用该类型。
    要获取存储在数据库中的枚举值,您可以使用:

    [Enum].Parse(enumType, value);
    

    其中 value 可以是整数值(0、1 等)或枚举文本/键(Apple、Banana 等)

    【讨论】:

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

    仅显示 Pandincus 的 answer 以及“现成”代码和一些解释: 这个例子你需要两个解决方案(我知道它也可以通过一个来完成;),让高级学生展示它......

    所以这里是表的 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
    

    【讨论】:

    • @YordanGeorgiev - 当flagFileExists 没有在应用程序的其他任何地方使用时,为什么要声明它?
    • 我猜这是一个错误,而不是 ;一)
    【解决方案7】:

    我们不是走错方向了吗?

    如果数据在部署版本的生命周期内可能发生变化,那么枚举是不合适的,您需要使用字典、散列或其他动态集合。

    如果您知道一组可能的值在已部署版本的生命周期内是固定的,那么最好使用枚举。

    如果您必须在您的数据库中有复制枚举集的内容,那么为什么不添加一个部署步骤来清除并使用确定的枚举值集重新填充数据库表?

    【讨论】:

    • 是的,不是的,是的,因为你是正确的,整点是枚举是静态的。您可以避免输入错误,也可以知道可用的内容。使用字典和数据库 - 可以是任何东西。但有时你想要两棵树的果实,而你只能从一棵树中采摘。
    【解决方案8】:

    我总是喜欢编写自己的“自定义枚举”。比我有一个更复杂的类,但我可以重用它:

    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    
    

    【讨论】:

      【解决方案9】:

      您需要 System.Web.Compilation.BuildProvider

      我也怀疑这样做是否明智,但也许有一个我想不出的好用例。

      您正在寻找的是 Build Providers 即 System.Web.Compilation.BuildProvider

      SubSonic 有效地使用了它们非常,您可以下载源代码并查看他们如何使用它们,您不需要像他们正在做的那样复杂的任何东西。

      希望这会有所帮助。

      【讨论】:

        【解决方案10】:

        无论哪种方式,使用动态枚举都是不好的。您将不得不经历“复制”数据的麻烦,以确保代码清晰易懂,便于将来维护。

        如果您开始引入自动生成的库,那么您肯定会给未来的开发人员带来更多的困惑,他们不得不升级您的代码,而不是简单地将您的枚举编码到适当的类对象中。

        给出的其他示例听起来不错且令人兴奋,但请考虑代码维护的开销与您从中获得的收益。另外,这些值是否会频繁更改?

        【讨论】:

          【解决方案11】:

          我认为没有什么好方法可以做你想做的事。如果你仔细想想,我认为这不是你真正想要的。

          如果您有一个动态枚举,这也意味着您必须在引用它时为其提供动态值。也许有很多魔法你可以实现某种IntelliSense 来处理这个问题并在DLL文件中为你生成一个枚举。但是考虑一下它所花费的工作量,访问数据库以获取 IntelliSense 信息的效率有多低,以及版本控制生成的 DLL 文件的噩梦。

          如果您真的不想手动添加枚举值(无论如何您都必须将它们添加到数据库中),请改用代码生成工具,例如 T4 模板。右键单击+运行,您就可以在代码中静态定义枚举,并获得使用枚举的所有好处。

          【讨论】:

            【解决方案12】:

            保留枚举并同时创建动态值列表的一种方法是将您当前拥有的枚举与动态创建的字典一起使用。

            由于大多数枚举是在定义它们使用的上下文中使用的,并且“动态枚举”将由动态进程支持,因此您可以区分2。

            第一步是创建一个表/集合,其中包含动态条目的 ID 和引用。在表格中,您的自动增量将远大于您的最大 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.
            

            【讨论】:

              【解决方案13】:

              枚举生成器类

              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();
              

              【讨论】:

                【解决方案14】:

                请注意,我也厌倦了根据 Id / Name db 表列编写枚举,从 SSMS 中的查询中复制和粘贴内容。

                下面是一个超级脏的存储过程,它以表名、要用于 c# 枚举名的列名和要用于 c# 枚举值的列名作为输入。

                我使用的大多数这些表名 a) 以“s”结尾 b) 有一个 [TABLENAME]Id 列并且 c) 有一个 [TABLENAME]Name 列,因此有几个 if 语句将假定该结构,在这种情况下,不需要列名参数。

                这些示例的一些背景信息 - 这里的“Stonk”并不是真正的“股票”,而是有点像我使用“stonk”的方式,它的意思是“在一段时间内有一些数字与之相关联的东西" 但这并不重要,它只是具有此 Id / Name 模式的表的示例。它看起来像这样:

                CREATE TABLE StonkTypes (
                    StonkTypeId TINYINT IDENTITY(1,1) PRIMARY KEY NOT NULL,
                    StonkTypeName VARCHAR(200) NOT NULL CONSTRAINT UQ_StonkTypes_StonkTypeName UNIQUE (StonkTypeName)
                )
                

                在我创建 proc 之后,这个语句:

                EXEC CreateCSharpEnum 'StonkTypes'

                选择这个字符串:

                public enum StonkTypes { Stonk = 1, Bond = 2, Index = 3, Fund = 4, Commodity = 5, 
                PutCallRatio = 6, }
                

                我可以将其复制并粘贴到 C# 文件中。

                我有一个 Stonks 表,它有 StonkId 和 StonkName 列,所以这个 exec:

                EXEC CreateCSharpEnum 'Stonks'
                

                吐出:

                public enum Stonks { SP500 = 1, DowJonesIndustrialAverage = 2, ..... }

                但是对于那个枚举,我想使用“符号”列作为枚举名称值,所以:

                EXEC CreateCSharpEnum 'Stonks', 'Symbol'
                

                诀窍和渲染:

                public enum Stonks { SPY = 1, DIA = 2, ..... }

                事不宜迟,这就是这个肮脏的疯狂。是的,很脏,但我对自己很满意——它是构建 C# 代码的 SQL 代码的 SQL 代码。涉及到几个层。

                
                CREATE OR ALTER PROCEDURE CreateCSharpEnum
                @TableName VARCHAR(MAX),
                @EnumNameColumnName VARCHAR(MAX) = NULL,
                @EnumValueColumnName VARCHAR(MAX) = NULL
                AS
                
                DECLARE @LastCharOfTableName VARCHAR(1)
                SELECT @LastCharOfTableName = RIGHT(@TableName, 1)
                
                PRINT 'Last char = [' + @LastCharOfTableName + ']'
                
                DECLARE @TableNameWithoutS VARCHAR(MAX)
                IF UPPER(@LastCharOfTableName) = 'S'
                    SET @TableNameWithoutS = LEFT(@TableName, LEN(@TableName) - 1)
                ELSE
                    SET @TableNameWithoutS = @TableName
                
                PRINT 'Table name without trailing s = [' + @TableNameWithoutS + ']'
                
                IF @EnumNameColumnName IS NULL
                    BEGIN
                        SET @EnumNameColumnName = @TableNameWithoutS + 'Name'
                    END
                
                PRINT 'name col name = [' + @EnumNameColumnName + ']'
                
                IF @EnumValueColumnName IS NULL
                    SET @EnumValueColumnName = @TableNameWithoutS + 'Id'
                
                PRINT 'value col name = [' + @EnumValueColumnName + ']'
                
                -- replace spaces and punctuation
                SET @EnumNameColumnName  = 'REPLACE(' + @EnumNameColumnName + ', '' '', '''')'
                SET @EnumNameColumnName  = 'REPLACE(' + @EnumNameColumnName + ', ''&'', '''')'
                SET @EnumNameColumnName  = 'REPLACE(' + @EnumNameColumnName + ', ''.'', '''')'
                SET @EnumNameColumnName  = 'REPLACE(' + @EnumNameColumnName + ', ''('', '''')'
                SET @EnumNameColumnName  = 'REPLACE(' + @EnumNameColumnName + ', '')'', '''')'
                
                PRINT 'name col name with replace sql = [' + @EnumNameColumnName + ']'
                
                DECLARE @SqlStr VARCHAR(MAX) = 'SELECT ' + @EnumNameColumnName  
                + ' + '' = ''' 
                + ' + LTRIM(RTRIM(STR(' + @EnumValueColumnName + '))) + '','' FROM ' + @TableName + ' ORDER BY ' + @EnumValueColumnName
                
                PRINT 'sql that gets rows for enum body = [' + @SqlStr + ']'
                
                CREATE TABLE #EnumRowsTemp (s VARCHAR(MAX))
                
                INSERT 
                INTO #EnumRowsTemp
                EXEC(@SqlStr)
                
                --SELECT * FROM #EnumRowsTemp
                
                DECLARE @csharpenumbody VARCHAR(MAX) 
                SELECT @csharpenumbody = COALESCE(@csharpenumbody + ' ', '') + s FROM #EnumRowsTemp
                
                --PRINT @csharpenumbody
                
                DECLARE @csharpenum VARCHAR(MAX) = 'public enum ' + @TableName + ' { ' + @csharpenumbody + ' }'
                
                PRINT @csharpenum
                
                SELECT @csharpenum
                
                DROP TABLE #EnumRowsTemp
                

                请保持批评。我不明白的一件时髦的事情是,为什么我必须创建和删除这个#EnumRowsTemp 表,而不仅仅是“SELECT INTO #EnumRowsTemp”来动态创建临时表?我不知道答案,我试过了,但没有用。这可能是这段代码中最少的问题......

                尽管它可能很脏...我希望这可以为你们中的一些笨蛋节省一点时间。

                【讨论】:

                • 哈我误读了这个问题,只是想找个地方发这个。但是,是的,你可以做反射的东西,但是......当你编写代码时,你将如何使用它?您必须编译新代码才能使用它。如果我必须这样做......你可以有一个 db 触发器或计划任务,然后运行反射的东西,编译一个 nuget 包等,等等,我同意这些家伙中的一些,这不是真正如何使用枚举。此代码将根据表格为您编写 c#,但您仍然必须将其复制并粘贴到 c# 文件中。仍然是手动过程。
                【解决方案15】:

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多