如何从我的应用程序处理SQL键值表

本文关键字:SQL 键值 处理 应用程序 我的 | 更新日期: 2023-09-27 18:01:59

所以我有一个简单的键值表BillTypes在我的SQL Server。它看起来像这样:

+----+-------------+
| Id | Description |
+----+-------------+
|  1 | OK          |
|  2 | Missing     |
|  3 | Maximum     |
|  4 | Minimum     |
|  5 | Error       |
+----+-------------+

表保存不同类型的账单状态。我有另一个表Items,外键BillType,引用上一个表中的Id。

+----------+------+--------+
| IdItem   | Cash |BillType|
+----------+------+--------+
| *        | *    | *      |
| *        | *    | *      |
| *        | *    | *      |
| ...      |...   | ...    |
+----------+------+--------+

然后,在我的应用程序中,我通过存储过程从第二个表中获取数据。在这个sp中,我不确定是应该选择BillType,还是tinyint,还是使用innerjoin来返回描述。问题是,我的应用程序有一些依赖于BillType的逻辑,即行将根据BillType进行不同的处理。我的逻辑应该依赖于Id还是描述?

在代码中,我应该有这样的东西吗?
DataTable dt = ...//call stored procedure that selects the BillType id
foreach(Datarow r in dt)
{
   if(r["BillType"] == 3) ... //use logic
}

还是这个?

DataTable dt = ...//call stored procedure that selects the BillType description
foreach(Datarow r in dt)
{
   if(r["BillType"] == "Maximum") ... //use logic
}

我目前使用第二种方式,带描述,因为我认为它使代码更具可读性。然而,我担心有人可能会更改描述并破坏我的应用程序逻辑。另一方面,使用id会降低可读性(尽管我可以使用enum来解决这个问题),并且不会受到描述更改的影响,但是如果有人更改了id,事情就会中断。

老实说,我们不希望任何人乱动第一个表,因为我们专门为这个应用程序制作了它。不过,我是SQL新手,我正在努力学习应用程序-SQL交互的最佳实践,所以我想知道有经验的人是如何做的

如何从我的应用程序处理SQL键值表

请将此视为评论而不是回答(我还没有足够的代表来评论)

我更喜欢后者(正如你所做的),我依赖于描述。

如果您的id是SQL标识字段(会自动增加),请考虑以下场景:

  1. 在DEV环境中构建应用程序和数据库
  2. 生产部署退出并重新运行
  3. 现在,id号不是1,2,3而是4,5,6

一般来说,依赖id比依赖值更有意义。毕竟,id应该是唯一的,而值可以有重复/更改。虽然您不希望对BillTypes表进行任何更改,但我不会像您建议的那样使用字符串值。

由于更新/删除/插入仍然可以在BillTypes表中发生,并且您希望准备好并具有可读的代码,因此最简单的方法是定义自己的enum:

public Enum BillTypesEnum
{
  OK = 1,
  Missing = 2,
  Maximum = 3,
  Minimum = 4,
  Error = 5
};

如果发生了什么事情,你需要添加一些东西到数据库,你这样做,然后改变Enum。如果删除"Error"条目并插入"Average"条目,它也可以工作。你不会得到平均值=5,但可能会得到平均值=6或更高的值。枚举结构使您可以毫无问题地定义值。

那么你就可以在整个代码中使用它,而不仅仅是在这个实例中。您的代码修改如下:

DataTable dt = ...//call stored procedure that selects the BillType id
foreach(Datarow r in dt)
{
   if(r["BillType"] == (int)BillTypesEnum.Maximum) ... //use logic
}

这使得代码比以前更具可读性,你不必在你的代码中硬编码所有的值,但只在一个地方。如果它发生了,你不会改变数据库,那么它就是一个加号。

另一个选项是执行spGetAllBillTypes (select * from tblBillTypes),然后在内部创建一个字典。

Dictionary<string,int> dictBillTypes = new Dictionary<string,int>();

int = billTypeIdstring = billTypeText

当您从子表(带有外键的表)检索数据时,您将检索您的billtypetext。

你可以这样做:

DataTable dt = ...//call stored procedure that selects the BillType id
foreach(Datarow r in dt)
{
   if(r["BillType"] == dictBillTypes["Maximum"]) ... //use logic
}

…但这仍然是一个不完整的解决方案,因为在这里,你依赖于两件事:1. billTypeText不会更改(如果更改了,则必须在代码中更改)2. billTypeText不能有重复项(否则你会得到一个关于字典中重复键值的异常)

另一个选项是把它转过来:

Dictionary<int,string> dict = new Dictionary<int,string>();

并根据值而不是键进行搜索。但这会使代码可读性降低,而且你并没有从中获得很多好处。

如果您担心ID更改,我建议创建一个Abstract Class来保存ID值。可以像引用Enum一样引用它,它将在第一次调用时查找ID,并缓存结果:

public abstract class BillType
{
    private static readonly string c_ok = "ok";
    private static readonly string c_missing = "missing";
    private static readonly string c_maximum = "maximum";
    private static readonly string c_minimum = "minumum";
    private static readonly string c_error = "error";
    private static int? _ok = null;
    private static int? _missing = null;
    private static int? _maximum = null;
    private static int? _minimum = null;
    private static int? _error = null;
    public static int OK
    {
        get
        {
            if (_ok == null)
                _ok = GetBillTypeID(c_ok);
            return (int)_ok;
        }
    }
    public static int Missing
    {
        get
        {
            if (_missing == null)
                _missing = GetBillTypeID(c_missing);
            return (int)_missing;
        }
    }
    public static int Maximum
    {
        get
        {
            if (_maximum == null)
                _maximum = GetBillTypeID(c_maximum);
            return (int)_maximum;
        }
    }
    public static int Minimum
    {
        get
        {
            if (_minimum == null)
                _minimum = GetBillTypeID(c_minimum);
            return (int)_minimum;
        }
    }
    public static int Error
    {
        get
        {
            if (_error == null)
                _error = GetBillTypeID(c_error);
            return (int)_error;
        }
    }

    private static int GetBillTypeID(string identifier)
    {
        using (SqlConnection conn = new SqlConnection("your connection string")
        {
            conn.Open();
            using (SqlCommand cmd = new SqlCommand("spGetBillTypeId", conn))
            {
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.AddWithValue("Description", identifier);
                return Convert.ToInt32(cmd.ExecuteScalar());
            }
        }
    }
}

我也会有一个Stored Procedure在你的数据库做查找ID:

Create Procedure spGetBillTypeId (@Description Varchar (20))
As Begin
    Select  Id
    From    BillTypes
    Where   Description = @Description
End

有了这个,您可以简单地调用BillType.Missing,它将提取缺失的Id,缓存它,并返回2

(注意,这大部分是复制/粘贴,所以注意随机错误,我没有捕捉到)。

如果您不希望值改变,但是,如果发生这种情况,您可以修改代码,您可以简单地创建一个Enum:

public enum BillType
{
    OK = 1,
    Missing = 2,
    Maximum = 3,
    Minimum = 4,
    Error = 5
}