Как читать родительские и дочерние данные из SQL? - PullRequest
2 голосов
/ 14 марта 2011

Еще раз спасибо за все замечательные ответы, которые вы все опубликовали!

У меня есть две таблицы в SQL. Первый определяет родительский элемент и имеет столбец первичного ключа с именем ParentId. У меня также есть дочерняя таблица с первичным ключом и внешним ключом «ParentId». Таким образом, две таблицы образуют отношения один родитель - много детей.

Вопрос в том, что является наиболее эффективным способом получения кода C # родительских и дочерних данных? Данные должны быть прочитаны в следующие объекты:

public class Parent
{
    public int ParentId { get; set; }
    public List<Child> Children { get; set; }
    //  ... many more properties ... //
}


public class Child
{
    public int ChildId { get; set; }
    public string Description { get; set; }
    //  ... many more properties ... //
}

Если я использую следующий запрос, я получу родителя и детей сразу, где каждый родитель будет повторяться столько раз, сколько у него будет детей:

SELECT
    p.ParentId as 'ParentId',
    c.ChildId as 'ChildId',
    -- other relevant fields --
FROM
    Parents p
INNER JOIN
    Children c
ON 
    p.ParentId = c.ParentId

Используя этот подход, мне нужно было бы найти все уникальные родительские строки, а затем прочитать все дочерние элементы. Преимущество в том, что я совершаю только 1 поездку в БД.

Второй вариант - читать всех родителей по отдельности:

SELECT * FROM Parents

и затем прочитайте всех детей отдельно:

SELECT * FROM Children

и используйте LINQ, чтобы объединить всех родителей с детьми. Этот подход делает 2 поездки в БД.

Третий и последний (также самый неэффективный) подход заключается в том, чтобы захватить всех родителей, и, создавая каждый родительский объект, отправиться в БД, чтобы захватить всех его потомков. Этот подход требует n + 1 соединений: 1 для всех родителей и n количество поездок для получения всех детей для каждого родителя.

Любой совет, как это сделать проще? Конечно, я не могу избежать использования хранимых процедур и не могу использовать LINQ2SQL или EF. Вы бы предпочли Таблицы данных, а не DataReaders, и если да, то как использовать их с подходом 1 или 2?

Спасибо, Martin

Ответы [ 4 ]

2 голосов
/ 15 марта 2011

Я предпочитаю вытягивать все результаты в одном запросе и просто строить дерево в одном цикле

    SELECT p.ParentId as 'ParentId', null as 'ChildId'
    FROM Parents p
    UNION ALL
    SELECT c.ParentId as 'ParentId', c.ChildId as 'ChildId'
    FROM Children c

    List<Parent> result = new List<Parent>();
    Parent current;
    while (dr.Read())
    {
      if (string.isNullOrEmpty(dr['ChildId']))
      {
        //create and initialize your parent object here and set to current
      }
      else if (!string.isNullOrEmpty(dr['ChildId']) 
                && dr['ParentId'].ToString().Equals(current.ParentId.ToString())
      {
        //create and initialize child
        //add child to parents child collection
      }
    }
1 голос
/ 15 марта 2011

При таком подходе мне нужно будет найти все уникальные родительские строки, а затем прочитать все дочерние элементы.

Вы можете просто включить order by p.ParentId.Это гарантирует, что все дети от одного и того же родителя находятся в последовательных строках.Таким образом, вы можете прочитать следующую строку, если родитель изменился, создайте новый родительский объект, в противном случае добавьте дочерний элемент к предыдущему родительскому объекту.Нет необходимости искать уникальные родительские строки.

0 голосов
/ 15 марта 2011

Я полагаю, что вариант № 2 будет более эффективным по сравнению с вариантом № 1 (поскольку вы не повторяете никаких данных).

Вы можете иметь оба запроса в одной хранимой процедуре и выполнять процедуру через код с использованием sqldataadapter (т. Е. (new SqlDataAdapter(command)).Fill(myDataSet), где myDataSet будет содержать две таблицы).

Оттуда вы читаете первую таблицу, создавая словарь родителей (в Dictionary<int, Parent>) по ParentId, а затем просто читаете каждую строку во 2-й таблице, чтобы добавить детей:

parents[(int)myDataSet.Tables[1]["ParentId"]].Children.Add(new Child() { etc } );

Псевдокод, вероятно, немного не в порядке, но, надеюсь, вы поймете общую идею

0 голосов
/ 15 марта 2011

Я обычно принимаю это решение на уровне таблицы.Некоторые столы мне часто нужны детям, поэтому я сразу их беру.В других случаях доступ к детям является редкостью, поэтому я их лениво загружаю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...