Опубликован: 11.09.2006 | Уровень: специалист | Доступ: свободно
Лекция 4:

Работа с данными

Объект Command

Объект Command применяется для выполнения SQL-запросов к источнику данных. Чтобы выполнить запрос, свойству Connection объекта Command следует задать объект "Имя" созданного Connection:

OleDbConnection  conn  =  new OleDbConnection();
conn.ConnectionString  =  ConnectionString;
conn.Open();
OleDbCommand myCommand = new OleDbCommand();
myCommand.Connection = conn;

Объект Connection также предоставляет метод CreateCommand, позволяющий упростить данный процесс — этот метод возвращает новый объект Command, уже инициализированный для использования вашего объекта Connection:

OleDbConnection  conn  =  new OleDbConnection();
conn.ConnectionString  =  ConnectionString;
conn.Open();
OleDbCommand myCommand = conn.CreateCommand();

Эти два способа совершенно эквивалентны.

Теперь нам следует определить SQL-запрос, который будет извлекать данные. Как и раньше, строкой, в которой будет содержаться этот запрос будет CommandText. Объявляем переменную CommandText, извлекающую все столбцы таблицы Customer:

string сommandText = @"SELECT Address1, Address2, City, [Contact First Name],
[Contact Last Name], [Contact Position], [Contact Title], Country, 
[Customer Credit ID], [Customer ID], [Customer Name], [E-mail], Fax, [Last Year'sSales], 
Phone, [Postal Code], Region, [Web Site] FROM Customer";
Листинг 4.14.

Объект myСommand имеет свойство, которое так и называется: CommandText. Чтобы избежать путаницы, изменим название переменной — CommandText на commandText (с маленькой буквы):

myCommand.CommandText = commandText;

Создаем объект OleDbDataAdapter:

OleDbDataAdapter dataAdapter = new OleDbDataAdapter();

Объект dataAdapter имеет свойство SelectCommand, в котором мы и будем указывать объект myCommand:

dataAdapter.SelectCommand = myCommand;

Создаем объект DataSet:

DataSet ds = new DataSet();

Заполняем ds данными из dataAdapter:

dataAdapter.Fill(ds, "Customers");

Указываем источник данных DataSource для dataGrid1:

dataGrid1.DataSource = ds.Tables["Customers"].DefaultView;

Закрываем соединение явным образом:

conn.Close();

Все! Запускаем приложение. Мы получили уже знакомый результат, но теперь мы действительно управляем всеми объектами, работающими с данными.

Полный листинг проекта ConnectionMDB:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Data.OleDb;

namespace ConnectionMDB
{
  /// <summary>
  /// Summary description for Form1.
  /// </summary>
  public class Form1 : System.Windows.Forms.Form
  {
    private System.Windows.Forms.DataGrid dataGrid1;
    string ConnectionString = 
      @"Provider=""Microsoft.Jet.OLEDB.4.0"";
      Data Source=""E:\Program Files\Microsoft Visual Studio .NET 2003\Crystal Reports\Samples\Database\xtreme.mdb"
      ";User ID=Admin;Jet OLEDB:Encrypt Database=False";
    string commandText = @"SELECT Address1, Address2, City, [Contact First Name], [Contact Last Name], 
      [Contact Position], [Contact Title], Country, [Customer Credit ID], [Customer ID], [Customer Name], 
      [E-mail], Fax, [Last Year's Sales], Phone, [Postal Code], Region, [Web Site] FROM Customer";


    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.Container components = null;

    public Form1()
    {
      //
      // Required for Windows Form Designer support
      //
      InitializeComponent();
      OleDbConnection  conn = new OleDbConnection(ConnectionString);
       //OleDbConnection  conn = new OleDbConnection(); 
//conn.ConnectionString = ConnectionString;
      conn.Open();
      OleDbCommand myCommand = new OleDbCommand();
      myCommand.Connection = conn;
      myCommand.CommandText = commandText;
      //OleDbCommand myCommand = conn.CreateCommand();
      myCommand.CommandText = commandText;
      OleDbDataAdapter dataAdapter = new OleDbDataAdapter();
      dataAdapter.SelectCommand = myCommand;
      DataSet ds = new DataSet();
      dataAdapter.Fill(ds, "Customers");
      dataGrid1.DataSource = ds.Tables["Customers"].DefaultView;
      conn.Close();
      //
      // TODO: Add any constructor code after InitializeComponent call
      //
    }

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    protected override void Dispose( bool disposing )
    {
      if( disposing )
      {
        if (components != null) 
        {
          components.Dispose();
        }
      }
      base.Dispose( disposing );
    }

    Windows Form Designer generated code
    
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main() 
    {
      Application.Run(new Form1());
    }

    private void Form1_Load(object sender, System.EventArgs e)
    {
    
    }
  }
}
Листинг 4.15.

Сравните использование строк ConnectionString и connectinText объектом myCommand с аналогичным использованием объектом DataAdapter (ProgrammDataMDB и ProgrammDataSQL).

Создание объекта Connection для базы данных SQL принципиально не отличается от примера, рассмотренного выше. В следующем фрагменте кода описываются те же объекты Connection и Command:

using System.Data.SqlClient;

string CommandText = "SELECT CustomerID, CompanyName, ContactName, ContactTitle, 
  Address, City, Region, PostalCode, Country, Phone, Fax FROM Customers";
string connectionString = "workstation id=7EA2B2F6068D473;integrated security=SSPI;
  data source=\"(local)\";persist security info=False;initial catalog=NorthwindCS";
      
SqlConnection  conn = new SqlConnection(connectionString);
 //SqlConnection  conn = new SqlConnection(); 
//conn.ConnectionString = ConnectionString;
      conn.Open();
      SqlCommand myCommand = new SqlCommand();
      myCommand.Connection = conn;
      myCommand.CommandText = CommandText;
      //SqlCommand myCommand = conn.CreateCommand();
      SqlDataAdapter dataAdapter = new SqlDataAdapter();
      dataAdapter.SelectCommand = myCommand;
      DataSet ds = new DataSet();
      dataAdapter.Fill(ds, "Customers");
      dataGrid1.DataSource = ds.Tables["Customers"].DefaultView;
      conn.Close();
Листинг 4.16.

На диске, прилагаемом к книге, вы найдете приложения ConnectionMDB и ConnectionSQL (Code\Glava4\ ConnectionMDB и ConnectionSQL).

У вас наверняка могло сложиться впечатление, что использование визуальных средств Microsoft Visual Studio .NET для добавления и конфигурирования объектов ADO.NET несравненно проще и логичней по сравнению с программным способом создания этих объектов. Однако это впечатление глубоко ошибочно. В действительности, только последний пример может претендовать на завершенное приложение — все остальные являются своего рода вспомогательными модулями. Повторюсь, что только полностью вручную написанный код объектов ADO.NET позволяет создавать ясные, надежные и гибкие приложения.

Вывод связанных таблиц

В начале этой лекции мы рассматривали две связанные таблицы — "Поставщики" и "Товары" базы данных Microsoft Access RBProduct (рис. 4.3). Элемент управления DataGrid позволяет представлять несколько связанных между собой таблиц.

Создайте новое приложение, назовите его DataGrid2Table. На создавшейся форме размещаем DataGrid, свойству этого элемента Dock устанавливаем значение Fill.

Подключаем пространство имен:

using System.Data.OleDb;

Создаем соединение и открываем его:

OleDbConnection conn = new OleDbConnection(connectionString);
conn.Open();

Создаем объект OleDbCommand и определяем для него соединение и строку CommandText:

OleDbCommand myCommand = new OleDbCommand();
myCommand.Connection = conn;
myCommand.CommandText = commandText;

Подключаемся к файлу базы данных Microsoft Access RBProduct.mdb, указываем соответствующие параметры строк connectionString и commandText:

string commandText = "SELECT [Адрес поставщика], [Код поставщика], Поставщик, 
Телефон FROM Поставщики";
string connectionString = @"Provider=""Microsoft.Jet.OLEDB.4.0"";Data 
Source=""D:\Uchebnik\Code\Glava4\RBProduct.mdb"";User ID=Admin;
Jet OLEDB:Encrypt Database=False";
Листинг 4.17.

Создаем объект DataAdapter и в свойстве SelectCommand устанавливаем значение myCommand:

OleDbDataAdapter dataAdapter = new OleDbDataAdapter();
dataAdapter.SelectCommand = myCommand;

Создаем объект DataSet:

DataSet ds = new DataSet();

В объекте DataSet здесь будут храниться две таблицы — главная и связанная с ней дочерняя. Поэтому воспользуемся свойством TableMappings объекта DataAdapter для занесения в него первой таблицы "Поставщики":

dataAdapter.TableMappings.Add("Table", "Поставщики");

Заполняем объект ds данными из dataAdapter:

dataAdapter.Fill(ds);

Свойству DataSource объекта dataGrid1 указываем таблицу "Поставщики" объекта ds. Обратите внимание на синтаксис — свойство Tables подразумевает наличие нескольких таблиц в объекте DataSet:

dataGrid1.DataSource = ds.Tables["Поставщики"].DefaultView;

Закрываем соединение:

conn.Close();

Запускаем приложение. Пока на форме появляется только одна таблица. Закрываем приложение и переходим в код формы. Теперь нам следует добавить объекты OleDbDataAdapter и OleDbCommand для таблицы "Товары":

OleDbCommand myCommand2 = new OleDbCommand();
myCommand2.Connection = conn;
myCommand2.CommandText = commandText2;
OleDbDataAdapter dataAdapter2 = new OleDbDataAdapter();

Обратите внимание — dataAdapter2 использует то же самое подключение conn, что и dataAdapter.

Строку commandText2 определим следующим образом:

string commandText2 = "SELECT [Код поставщика], [Код продукта], 
Наименование, [Цена, $] FROM Товары";

Теперь свяжем второй объект OleDbDataAdapter с только что созданной второй командой и отобразим "Товары" на его таблицу. Затем можно заполнить объект DataSet данными из второй таблицы:

dataAdapter2.SelectCommand = myCommand2;
dataAdapter2.TableMappings.Add("Table", "Товары");
dataAdapter2.Fill(ds);

В итоге у нас получился объект DataSet с двумя таблицами. Теперь можно выводить одну из этих таблиц на форму или две сразу. Но связь между таблицами еще не создана. Объявим объект DataRelation:

DataRelation dataRelation;

Этот объект будет представлять собой отношение между таблицами, связанными по полю "Код поставщика" (см. рис. 4.2). Для конфигурирования этого отношения нам понадобятся два объекта типа DataColumn:

DataColumn dataColumn1;
DataColumn dataColumn2;

Присваиваем каждому из этих объектов поле, по которому связаны таблицы:

dataColumn1 = ds.Tables["Поставщики"].Columns["Код поставщика"];
dataColumn2 = ds.Tables["Товары"].Columns["Код поставщика"];

Конструктору объекта dataRelation передаем имя отношения между таблицами и два объекта DataColumn:

dataRelation = new DataRelation("Товары этого поставщика", 
dataColumn1,dataColumn2);

Добавляем созданный объект отношения к объекту DataSet:

ds.Relations.Add(dataRelation);

Создаем объект DataViewManager, отвечающий за отображение DataSet в объекте DataGrid:

DataViewManager dsview = ds.DefaultViewManager;

Присвоим свойству DataSource объекта DataGrid созданный объект DataViewManager:

dataGrid1.DataSource = dsview;

Последнее, что нам осталось сделать, — сообщить объекту DataGrid, какую таблицу считать главной (родительской) и соответственно отображать на форме:

dataGrid1.DataMember = "Поставщики";

Закрываем соединение:

conn.Close();

Запускаем приложение. Теперь можно просматривать товары, поставляемые поставщикам, в том же самом виде, как это было реализовано в Microsoft Access (рис. 4.49 и 4.50).

С главной таблицы мы можем перейти на дочернюю

Рис. 4.49. С главной таблицы мы можем перейти на дочернюю
Для возврата на главную форму можно использовать встроенную кнопку элемента управления DataGrid

Рис. 4.50. Для возврата на главную форму можно использовать встроенную кнопку элемента управления DataGrid

Полный листинг проекта DataGrid2Table:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Data.OleDb;

namespace DataGrid2Table
{
  /// <summary>
  /// Summary description for Form1.
  /// </summary>
  public class Form1 : System.Windows.Forms.Form
  {
    private System.Windows.Forms.DataGrid dataGrid1;
    string commandText = "SELECT [Адрес поставщика], [Код поставщика], Поставщик, Телефон FROM Поставщики";
    string connectionString = @"Provider=""Microsoft.Jet.OLEDB.4.0"";
      Data Source=""D:\Uchebnik\Code\Glava4\RBProduct.mdb"";User ID=Admin;Jet OLEDB:Encrypt Database=False";
    string commandText2 = "SELECT [Код поставщика], [Код продукта], Наименование, [Цена, $] FROM Товары";
      
      
    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.Container components = null;

    public Form1()
    {
      //
      // Required for Windows Form Designer support
      //
      InitializeComponent();
      OleDbConnection conn = new OleDbConnection(connectionString);
      conn.Open();
      OleDbCommand myCommand = new OleDbCommand();
      myCommand.Connection = conn;
      myCommand.CommandText = commandText;
      OleDbDataAdapter dataAdapter = new OleDbDataAdapter();
      dataAdapter.SelectCommand = myCommand;
      DataSet ds = new DataSet();
      dataAdapter.TableMappings.Add("Table", "Поставщики");
      dataAdapter.Fill(ds);
      dataGrid1.DataSource = ds.Tables["Поставщики"].DefaultView;
      OleDbCommand myCommand2 = new OleDbCommand();
      myCommand2.Connection = conn;
      myCommand2.CommandText = commandText2;
      OleDbDataAdapter dataAdapter2 = new OleDbDataAdapter();
      dataAdapter2.SelectCommand = myCommand2;
      dataAdapter2.TableMappings.Add("Table", "Товары");
      dataAdapter2.Fill(ds);
      DataRelation dataRelation;
      DataColumn dataColumn1;
      DataColumn dataColumn2;
      dataColumn1 = ds.Tables["Поставщики"].Columns["Код поставщика"];
      dataColumn2 = ds.Tables["Товары"].Columns["Код поставщика"];
dataRelation = new DataRelation("Товары этого поставщика", dataColumn1, dataColumn2);
      ds.Relations.Add(dataRelation);
      DataViewManager dsview = ds.DefaultViewManager;
      dataGrid1.DataSource = dsview;
      dataGrid1.DataMember = "Поставщики";
      conn.Close();
      //
      // TODO: Add any constructor code after InitializeComponent call
      //
    }

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    protected override void Dispose( bool disposing )
    {
      if( disposing )
      {
        if (components != null) 
        {
          components.Dispose();
        }
      }
      base.Dispose( disposing );
    }

    Windows Form Designer generated code
    

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main() 
    {
      Application.Run(new Form1());
    }

    
  }
}
Листинг 4.18.

На диске, прилагаемом к книге, вы найдете проект DataGrid2Table (Code\Glava4\ DataGrid2Table).

Елена Дьяконова
Елена Дьяконова

При нажатии на Сумма в примере ArbitraryMethod из Лекция 7, VS 2013 выдается ошибка: 

Необработанное исключение типа "System.InvalidOperationException" в System.Windows.Forms.dll

Дополнительные сведения: Недопустимая операция в нескольких потоках: попытка доступа к элементу управления "lblResult" не из того потока, в котором он был создан.

Затем:

Необработанное исключение типа "System.InvalidOperationException" в mscorlib.dll

Дополнительные сведения: Для каждой асинхронной операции метод EndInvoke может вызываться только один раз.

Александр Сороколет
Александр Сороколет

Свойство WindowState формы blank Maximized. Не открывается почемуто на всё окно, а вот если последующую форму бланк открыть уже на макс открывается :-/