C # несколько соединений с набором данных - PullRequest
3 голосов
/ 26 февраля 2009

Я использую C # и SQL Server 2005, и мне нужна рекомендация о том, как заполнять мои объекты.

У меня есть коллекция Customers, содержащая коллекцию объектов customer. Каждый объект customer содержит коллекцию Orders, содержащую коллекцию заказов.

Я использую публичный метод Fetch () в своей коллекции Customers для заполнения клиентов и их заказов.

Вы можете иметь только один DataReader, открытый для каждого соединения, верно. Таким образом, это означает, что мне нужно одно соединение для считывателя «SELECT * Customers», и, пока я выполняю итерацию через считыватель клиентов, мне потребуется другое соединение для каждого «SELECT * Orders» WHERE CustomerId_fk = @Id ».

Мой вопрос: Вы бы порекомендовали использовать вышеуказанный способ или просто использовать DataSets?

EDIT

У меня было «ВЫБРАТЬ * Клиентов, ГДЕ Id = @Id» вместо «ВЫБРАТЬ * Клиентов».

Ответы [ 4 ]

3 голосов
/ 26 февраля 2009

На самом деле ваше утверждение («У вас может быть только один DataReader, открытый на одно соединение») неверно; вы можете включить MARS (несколько активных результирующих наборов) через настройку строки подключения, и работа сделана; за исключением того, что у вас все равно будет много поездок туда и обратно (n + 1).

Я также не думаю, что непосредственной альтернативой являются наборы данных. Лично я бы использовал две таблицы результатов (либо из одного запроса, либо из двух запросов) и соединил их обратно в вызывающей стороне.

В качестве альтернативы используйте что-то вроде LINQ-to-SQL с LoadWith<Customer>(c=>c.Orders); (DataLoadOptions). Даже без LoadWith он будет выполнять то же самое поведение n + 1 автоматически, просто загружая коллекцию для каждого Customer (свойства навигации загружаются лениво по умолчанию).

2 голосов
/ 26 февраля 2009

Я бы, вероятно, использовал SqlDataAdapter для запроса обоих за один проход в DataSet. Примерно так:

SqlDataAdapter adapter = new SqlDataAdapter("SELECT * FROM CUSTOMERS WHERE CustomerId = @id; SELECT * FROM ORDERS WHERE CustomerId = @id",connection);
adapter.Fill(dataSet);

Тогда я бы установил отношение, используя что-то вроде этого:

dataSet.Relations.Add(new DataRelation("relationName", dataSet.Tables[0].Columns["CustomerId"], dataSet.Tables[1].Columns["CustomerId"]);

Таким образом, вы открываете только одно соединение, запрашиваете все данные, а затем устанавливаете связь в памяти.

1 голос
/ 26 февраля 2009

Я просто расширю ответ Марка. DataReader может читать несколько результирующих наборов одновременно. Таким образом, вы можете сделать следующее:

string sql = "SELECT * FROM Customers; SELECT * FROM Orders;";
using (SqlCommand cmd = new SqlCommand(sql, connection))
using (SqlDataReader rd = cmd.ExecuteReader())
{

  while (rd.Read())
  {
    // Read customers
  }

  if (rd.NextResult())  // Change result set to Orders
  {
    while(rd.Read())
    {
      // Read orders
    }

  }
}

Вы бы, конечно, только получили необходимые данные, но вы поняли. Это позволяет получить оба набора результатов с помощью одной команды.

0 голосов
/ 26 февраля 2009

Черт! Я бы просто укусил мою руку и использовал два соединения.

Не забудьте закрыть их и устройство чтения данных.

Не знаю, почему, я просто не могу заставить себя использовать DataSet где-нибудь ...!

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