C# 枚举还是表?

C# 枚举还是表?,c#,enums,C#,Enums,我把它变成一个社区维基,因为我会欣赏人们的方法,而不一定是答案 我的情况是,我有很多查找类型的数据字段,这些字段不会改变。例如: 年薪 选项:0-25K 选项:25K-100K 选项:10万+ 我希望这些选项可以通过枚举轻松获得,但也希望数据库中的文本值可用,因为我将报告文本值而不是ID。此外,由于它们是静态的,我不希望调用数据库 我想在枚举和表中复制这个,但想听听其他想法 谢谢我认为枚举是个坏主意。仅考虑到您显示的数据类型,它可能会发生更改。最好有一个带有ID/Min/Max/Descript

我把它变成一个社区维基,因为我会欣赏人们的方法,而不一定是答案

我的情况是,我有很多查找类型的数据字段,这些字段不会改变。例如:

年薪
选项:0-25K
选项:25K-100K
选项:10万+

我希望这些选项可以通过枚举轻松获得,但也希望数据库中的文本值可用,因为我将报告文本值而不是ID。此外,由于它们是静态的,我不希望调用数据库

我想在枚举和表中复制这个,但想听听其他想法


谢谢

我认为枚举是个坏主意。仅考虑到您显示的数据类型,它可能会发生更改。最好有一个带有ID/Min/Max/Description字段的数据库表,在应用程序初始化时加载这些字段。

我同时使用这两个字段。在LINQtoSQL和EF中,只需将列属性设置为枚举类型。在其他框架中,通常可以以某种方式将列映射到枚举属性。数据库中仍然可以有一个包含有效枚举的主键表


您也可以通过数据库中的检查约束来实现这一点,但这往往会将您的数据与应用程序绑定在一起—仅查看数据库的人不一定知道每个值的含义。因此,我更喜欢混合表/枚举。

首先确保此数据是真正静态的。如果有任何变化,您将不得不重新编译和重新部署

如果数据真的是静态的,我会选择枚举路径。您可以创建一个包含所有值的
YearlySalaryEnum
。对于字符串表示,我将使用带有字符串值的字典,并将
yearlysalarynum
作为键。字典可以作为静态类中的静态实例保存。用法大致如下(C#):


使用枚举(用于代码)和DB文本(用于GUI演示)


因此,如果您总是有3个选项使用enum
LowSalary
MiddleSalary
HighSalary
,请将文本存储在DB中,并在GUI中切换与属性enum值对应的文本。

同时使用这两个选项,您应该调查代码域。使用此功能,您可以编写代码生成例程,允许编译过程通过读取数据库自动生成包含这些枚举的程序集或类。这样,您可以让数据库驱动,但不是每次访问枚举实例时都调用数据库

由于C#不允许使用字符串值的枚举,因此我建议使用带有一些静态字符串的结构

通过这种方式,您可以维护一些Intellisense,但不需要尝试在数据库中的字符串值上强加枚举值


我将提供的另一个解决方案是:删除依赖于这些值的逻辑,并转移到基于表的逻辑。(例如,如果每个traunch具有不同的税率,请将税率作为列添加到数据库中,而不是代码中的{}。)。

一种方法是编写一个格式化程序,将枚举转换为字符串表示形式:

public class SalaryFormatter : IFormatProvider, ICustomFormatter
{
    public object GetFormat(Type formatType)
    {
         return (formatType == typeof(ICustomFormatter)) ? new
         SalaryFormatter () : null;
    }

    public string Format(string format, object o, IFormatProvider formatProvider)
    {
        if (o.GetType().Equals(typeof(Salary)))
        {
            return o.ToString();

            Salary salary = (Salary)o;
            switch (salary)
            {
                case Salary.Low:
                     return "0 - 25K";
                case Salary.Mid:
                     return "25K - 100K";
                case Salary.High:
                     return "100K+";
                default:
                     return salary.ToString();
            }
        }

    return o.ToString();
    }
}
您可以像使用任何其他格式化程序一样使用格式化程序:

Console.WriteLine(String.Format(new SalaryFormatter(), "Salary: {0}", salary));

格式化程序可以通过格式化字符串、多种类型、本地化等扩展以支持不同的格式。

看看我的建议

基本上,我对核心查找数据使用默认值sql脚本,对来自其他表的FK引用使用ID,然后使用简单的T4模板生成c#的枚举。这样,数据库就高效、规范化和正确约束,我的c#实体不必处理ID(幻数)

它很简单,快速,简单,为我做的工作


我使用EF4,但您不需要,可以将这种方法用于您的实体使用的任何技术

对于静态项,我为每个元素使用带有[Description()]属性的Enum。 和T4模板,用于重新生成带有生成说明的枚举(或在需要时)

像这样使用它

string str = EnumSalary.Mid.Description()
p.S.还为System.Enum创建了扩展

public static string Description(this Enum value) {
    FieldInfo fi = value.GetType().GetField(value.ToString());
    var attributes = (DescriptionAttribute[]) fi.GetCustomAttributes(typeof(DescriptionAttribute), false );
    return attributes.Length > 0 ? attributes[0].Description : value.ToString();
}
和反转以按描述创建枚举

public static TEnum ToDescriptionEnum<TEnum>(this string description)
{
    Type enumType = typeof(TEnum);
    foreach (string name in Enum.GetNames(enumType))
    {
        var enValue = Enum.Parse(enumType, name);
        if (Description((Enum)enValue).Equals(description)) {
            return (TEnum) enValue;
        }
    }
    throw new TargetException("The string is not a description or value of the specified enum.");
}
公共静态TEnum ToDescriptionEnum(此字符串描述)
{
类型enumType=typeof(TEnum);
foreach(Enum.GetNames(enumType)中的字符串名)
{
var enValue=Enum.Parse(enumType,name);
if(Description((Enum)enValue).Equals(Description)){
回报(十纳姆)环境价值;
}
}
抛出新的TargetException(“字符串不是指定枚举的描述或值”);
}

SQL报告的功能如何?如何使用仅枚举的方法解决这个问题。从DB初始化字典,非常简单。如果枚举后面的数据类型是整数,那么将其映射到db列是很简单的。正如Aaron所指出的,许多ORM都可以开箱即用,这就是一个例子,它不会改变。不管怎样,我喜欢您的方法,您将如何在整个应用程序中保持数据。99%的应用程序不需要这些数据,这会不会有任何性能问题?如果很少访问这些数据,您可以将其保存在一个静态类中,该类在您第一次请求数据时初始化(延迟初始化)。只需确保锁已到位,以便一次只有一个线程可以访问该数据。这将消除任何启动减速。如果您不想在第一次访问数据时等待,还可以将数据加载到低优先级工作队列中,以便在数据空闲一两分钟时加载(或在需要之前立即加载)如果它真的不会改变,并且你没有数据库,你可以将它存储在你的app.config文件中的一个自定义部分。真的,我不明白这里的意思。如果文本发生更改,它应该在数据库中,但当您从数据库加载它时,您会将它与枚举相关联。这就是感觉
public static string Description(this Enum value) {
    FieldInfo fi = value.GetType().GetField(value.ToString());
    var attributes = (DescriptionAttribute[]) fi.GetCustomAttributes(typeof(DescriptionAttribute), false );
    return attributes.Length > 0 ? attributes[0].Description : value.ToString();
}
public static TEnum ToDescriptionEnum<TEnum>(this string description)
{
    Type enumType = typeof(TEnum);
    foreach (string name in Enum.GetNames(enumType))
    {
        var enValue = Enum.Parse(enumType, name);
        if (Description((Enum)enValue).Equals(description)) {
            return (TEnum) enValue;
        }
    }
    throw new TargetException("The string is not a description or value of the specified enum.");
}