基于SQL中的一对多表关系填充对象

时间:2011-08-02 20:12:36

标签: c# sql one-to-many

我在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();
    }
}

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

3 个答案:

答案 0 :(得分:4)

我会使用表连接。创建一个遍历结果的方法非常简单。即使在查询多个小部件及其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();
        }
    }
}

答案 1 :(得分:0)

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

答案 2 :(得分:0)

我认为您应该开始转向Ado Entity Framework或LinQ to SQL作为数据提供者,因为它将为您节省大量时间,并且它将以有效的方式完成您想要的任务。