【问题标题】:Populating an object based on a one-to-many table relationship in SQL基于 SQL 中的一对多表关系填充对象
【发布时间】:2011-08-03 04:31:59
【问题描述】:

我在 C# 中有一个像这样的对象:

private ClassWidget
{
    public int ID;
    public List<int> WidgetFavoriteNumbers;
}

假设我在 SQL 中有两个表,一个定义小部件属性,另一个保存单个小部件的许多记录,假设是小部件最喜欢的数字:

widgets
-----------
id (int, not null)
// other properties ...

widget_nums
----------
widget_id (int, not null)
num (int)

我发现自己经常执行两个 SQL 查询来填充这个对象,尽管我知道我可以连接这些表来创建一个查询。原因是用我需要的数据填充对象似乎更简单,而不是迭代具有大量重复数据的结果集。当然,与真实场景相比,这个小部件示例要简化得多。示例如下:

int WidgetID = 8;
ClassWidget MyWidget = new ClassWidget();
using (SqlConnection conn = GetSQLConnection())
{
    using (SqlCommand cmd = conn.CreateCommand())
    {
        conn.Open();
        cmd.CommandText = @"SELECT id FROM widgets WHERE id = @WidgetID;";
        cmd.Parameters.AddWithValue("WidgetID", WidgetID);
        using (SqlDataReader Reader = cmd.ExecuteReader())
        {
            if (Reader.HasRows)
                MyWidget.ID = GetDBInt("id", Reader); // custom method to read database result
        }
        cmd.CommandText = @"SELECT num FROM widget_nums WHERE widget_id = @WidgetID;";
        using (SqlDataReader Reader = cmd.ExecuteReader())
        {
            if (Reader.HasRows)
                while (Reader.Read())
                    MyWidget.WidgetFavoriteNumbers.Add(GetDBInt("num", Reader));
        }
        conn.Close();
    }
}

我的问题是我是否应该继续使用这种方法,或者是否建议执行表连接。如果推荐使用表连接,那么填充对象的最佳设计模式是什么?我的问题是我必须创建一些逻辑来过滤掉重复的行,当我获取所有小部件而不是一个小部件时尤其复杂。

【问题讨论】:

    标签: c# sql one-to-many


    【解决方案1】:

    我会使用表连接。创建一个遍历结果的方法非常简单。即使在查询多个小部件及其 widget_nums 时,您也可以使用此方法

      private IEnumerable<ClassWidget> MapReaderToWidget(IDataReader reader) {
         var dict = new Dictionary<int, ClassWidget>();
         while (reader.Read()) {
            var id = (int)reader["id"];
            ClassWidget widget;
            if (!dict.TryGetValue(id, out widget)) {
                widget = new ClassWidget {
                   ID = id,
                   WidgetFavoriteNumbers = new List<int>();
                };
                dict.Add(id, widget);
            }
            widget.WidgetFavoriteNumbers.Add((int)reader["num"]);
         }
         return dict.Values;
      }
    

    然后重写你的方法如下:

    using (SqlConnection conn = GetSQLConnection())
    {
        using (SqlCommand cmd = conn.CreateCommand())
        {
            conn.Open();
            cmd.CommandText = @"SELECT id FROM widgets INNER JOIN widget_nums on .... WHERE id = @WidgetID;";
            cmd.Parameters.AddWithValue("WidgetID", WidgetID);
            using (SqlDataReader Reader = cmd.ExecuteReader()) {
               return MapReaderToWidget(reader).FirstOrDefault();
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      使用表连接。它使用单个 SQL 查询,而且速度非常快(比您当前的方法快得多)。对于过滤重复行的逻辑,你可以想出一个查询,我想;花一些时间来开发一个查询,它可以为您提供您想要从数据库中获得的内容,并且您会对结果感到满意。

      【讨论】:

        【解决方案3】:

        我认为您应该开始迁移到 Ado Entity Framework 或 LinQ to SQL 作为您的数据提供者,因为它可以为您节省大量时间,并且它会以一种有效的方式完全满足您的需求。

        【讨论】:

        • 我确实喜欢 ORM 的想法,但是在调试时,这并不意味着您不会彻底了解数据层,因此您最终会遍历它进行调试?
        • 对不起,我没明白你的意思?!
        • 我的经验有限,但我相信如果您编写自己的数据层而不是使用数据提供程序,调试会容易得多?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-16
        • 1970-01-01
        • 1970-01-01
        • 2020-11-22
        • 2019-09-14
        • 2021-12-14
        相关资源
        最近更新 更多