ADO.NET. Управление базами данных. Связь по схеме OLE DB провайдера. Коррекция стилей DataGridView, страница 50

AND C.CustomerID = O.CustomerID AND O.OrderID = OD.OrderID AND OD.ProductID = P.ProductID

GROUP BY ProductName

Параметр определяет индекс строки в таблице Customers, но работа в процедуре ведется с четырьмя таблицами базы NorthWind (Products, Order Details, Orders и Customers). Логика выбора данных сосредоточена в части WHERE оператора SELECT. Здесь происходит спуск по связанным таблицам, начиная от таблицы Customers и заканчивая таблицей Products. Цепочка обращений к данным использует первичные и связанные ключи указанных таблиц и выглядит следующим образом: Customers®Orders®Order Details®Products.

·  По индексу покупателя CustomerID находятся его заказы,

·  По индексу заказа OrderID определяются его детали (индекс продукта).

·  По индексу продукта ProductID определяется его наименование.

·  Наименование продукта поступает в первую колонку результирующей таблицы.

·  Во вторую колонку помещаются суммы закупок этих продуктов клиентом с индексом CustomerID.

Рассмотрим код, который пользуется хранимой процедурой CustOrderHist и выводит результаты в консольное окно. Код клиента ("ALFKI") задан жестко, но может быть произвольным. Для демонстрации результатов явно напрашивается компонент PieChart, который мы рассматривали в предыдущем семестре.

string clientID = "ALFKI";

SqlCommand cmd = new SqlCommand ("CustOrderHist", сn);

cmd.CommandType = CommandType.StoredProcedure;

SqlParameter par = cmd.Parameters.Add(

   new SqlParameter("@CustomerID", SqlDbType. VarChar, 5, "CustomerID"));

par.Value = clientID;

SqlDataReader reader = cmd.ExecuteReader();

Console.WriteLine("\n{0,-32}{1}", reader.GetName(0), reader.GetName(1));

while (reader.Read())

  Console.WriteLine("{0,-35}{1,2}", reader.GetString(0), reader.GetInt32(1));

reader.Close();

сn.Close();

В этот момент стоит задуматься о той работе, которую проводит ядро СУБД для реализации логики сложных запросов. В учебных целях рассмотрим код, который реализует примерно ту же логику, что и хранимая процедура, но делает постепенно, с помощью серии более простых запросов. Цель упражнения—научиться управлять параметрами команды SELECT. Сначала запросим (и запомним в коллекции orders) индексы всех заказов данного клиента.

string clientID = "ALFKI";

SqlCommand cmd = new SqlCommand(

  "SELECT OrderID From Orders WHERE CustomerID=@CustomerID", cn);

SqlParameter par = cmd.Parameters.Add(new SqlParameter(

  "@CustomerID", SqlDbType.VarChar, 5, "CustomerID"));

par.Value = clientID;

cn.Open();

SqlDataReader reader = cmd.ExecuteReader();

ArrayList orders = new ArrayList();

Console.WriteLine("{0}", reader.GetName(0));

while (reader.Read())

{

  orders.Add (reader.GetInt32(0));

  Console.WriteLine("{0}", orders[orders.Count-1]);

}

reader.Close();

Затем запросим (и запомним в коллекции idQuant) пары (продукт, количество), которые соответствуют индексам заказов, найденных на первом шаге. Обратите внимание на условный оператор внутри цикла чтения.

cmd = new SqlCommand(

  "SELECT ProductID, Quantity From [Order Details] WHERE OrderID=@OrderID", сn);

par = cmd.Parameters.Add (new SqlParameter ("@OrderID", SqlDbType.Int));

SortedList idQuant = new SortedList();

foreach (int orderID in orders)

{

  par.Value = orderID;

  reader = cmd.ExecuteReader();

  Console.WriteLine("\nOrder = {0}\nProductID   Quantity", orderID);

  while (reader.Read())

  {

   int pID = reader.GetInt32(0),

      q = reader.GetInt16(1);

   if (idQuant.Contains(pID))

    idQuant[pID] = (int)idQuant[pID] + q;

   else

    idQuant.Add (pID, q);

   Console.WriteLine("{0,-10}{1}", pID, q);

  }

  reader.Close();

}

На последнем шаге алгоритма получим пары (индекс продукта, продукт). Здесь используются результаты второго шага. Вывод в удобном для нас формате (тройки объектов) производим с помощью данных двух последних шагов. Алгоритм показывает, что одни и те же объекты ADO.NET можно перенастраивать и использовать повторно при вызове метода ExecuteReader.