Заполнение объекта на основе отношения таблицы «один ко многим» в SQL - PullRequest
3 голосов
/ 03 августа 2011

У меня есть объект в 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 ]

4 голосов
/ 03 августа 2011

Я бы использовал объединение таблиц. Довольно просто создать метод, который будет пересекать результаты. Вы можете использовать этот метод даже при запросе нескольких виджетов и их 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();
        }
    }
}
0 голосов
/ 03 августа 2011

Я думаю, вам следует начать переходить на Ado Entity Framework или LinQ to SQL в качестве поставщика данных, поскольку это сэкономит вам много времени и будет эффективно выполнять то, что вы хотите.

0 голосов
/ 03 августа 2011

Используйте объединение таблиц. Он использует один SQL-запрос, и это очень быстро (гораздо быстрее, чем ваш нынешний подход). И для логики, чтобы отфильтровать дублирующиеся строки, вы можете придумать запрос для этого, я думаю; Потратьте некоторое время на разработку запроса, который даст вам то, что вы хотите из базы данных, и вы будете довольны результатами.

...