Файлы к лабораторной работе Вы можете скачать здесь.
Однажды в студентную зимнюю пору Виталя Биктимиров сказал про Visual Studio .NET 2003 такие мудрые слова: "Я знал, что там все разложено по полочкам, но я не подозревал, что этих полок окажется так много" !!! А вот тебе, Виталя, еще целый стеллаж...
Студент Панасюк, если серьезно заниматься разработкой приложений,
то чтобы добыть достаточное количество сала,
без знаний о базах данных не обойтись. В каждом потенциальном
Заказчике Вы обязательно встретите лукавую ухмылку и коварный
вопрос, а можете ли Вы разрабатывать приложения для управления
большими объемами данных. Поэтому знание
Данные имеют разные формы и размеры и в мире существует великое
множество способов хранения данных. Вероятность появления у
клиента желания перейти на базу данных другого производителя
очень велика. Поэтому, чтобы судорожно не переучиваться на
голодный желудок, необходимо владеть знанием универсального
механизма доступа и
Технология .NET представляет собой совершенно новый способ
программирования, предполагающий наличие управляемой исполняющей
среды и механизма
Для решения задач программного localhost. Возможно,
перед этим файлы
придется скопировать в папку C:\MSSQL7\Data. Установите обе учебных базы, т.к. они нам в дальнейшем понадобятся именно обе.

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

В этой панели отображается дерево доступных сервисов, среди которых можно увидеть установленные базы данных, в том числе нужные нам Northwind и pubs (на данном этапе нам понадобится только база Northwind, но в дальнейшем, даст Бог, доберемся и до второй)

Далее мы будем употреблять термины, в которые вложен одинаковый смысл:
BCL -
Для создания приложений с
Если известно, что для приложения должна использоваться база
данных типа SQL Server, то для обеспечения более высокой производительности
этого приложения следует применять классы, которые относятся
к пространству имен System.Data.SqlClient.
Но если тип базы данных, применяемой в приложении заранее не
известен, то следует использовать классы пространства имен System.Data.OleDb
![]() |
![]() |
На вкладке Data панели Toolbox соответствующие компоненты
имеют префиксы Sql и OleDb

| Компонент | Назначение |
|---|---|
|
Используется в сочетании с другими компонентами и позволяет
хранить результаты, возвращенные командами и дают возможность
получить полный доступ к отдельным таблицам, строкам и
столбцам. |
OleDbDataAdapter |
Дает возможность управлять командами, которые должны
быть применены к такому провайдеру данных OleDb, как Jet, Oracle или SQL Server, и хранить их. В частности, могут
применяться команды выборки, обновления, вставки и удаления
записей. Отслеживается также объект соединения Connection,
к которому применяются эти команды. |
OleDbConnection |
Позволяет сопровождать информацию о соединении для OleDb. Он применяется в сочетании с компонентом OleDbDataAdapter. |
OleDbCommand |
Как и объект команды |
SqlDataAdapter |
Аналогичен компоненту OleDbDataAdapter за исключением
того, что он применяется для доступа только к хранилищам
данных SQL Server. |
|
Аналогичен компоненту OleDbConnection за исключением
того, что он применяется для доступа только к хранилищам
данных SQL Server. |
SqlCommand |
Аналогичен компоненту OleDbCommand за исключением того,
что он применяется для доступа только к |
DataView |
Позволяет создавать несколько представлений одной и той же таблицы. В частности, он обеспечивает возможность просматривать данные, находящиеся в различных состояниях, например, удаленные, модифицированные или как-то отсортированные. |
В качестве упражнения создадим соединение с учебной базой данных Northwind, которая поставлется вместе с оболочкой Visual Studio .NET 2003, но которая есть в каталоге Data данной работы.
Войдите
в каталог предполагаемого размещения своей работы и создайте
новый проект приложения 
Раскройте
вкладку Data панели Toolbox и перенесите на форму компонент OleDbDataAdapter.Откроется окно мастера настройки конфигурации

В раскрывающемся списке
("Which data connection should data
Щелкните
на кнопке New Connection..., после чего откроется окно 
После
щелчка на кнопке OK вновь появится предыдущее окно мастера
в котором выберите созданное соединение и щелкните на кнопке Next.
Появится
новое окно мастера, в котором оставьте опцию по умолчанию Use SQL statements (использовать 
и щелкните по кнопке Next.
Откроется поле ввода, обозначенное вопросом What data
should the data adapter load into the dataset? (Какие
данные должны загружаться этим

Введите
в поле ввода Select CustomerID, CompanyName From Customers
Щелкните
на кнопке 
Щелкните
на кнопке Next для просмотра результатов выполнения оператора
выборки. Если Вы все сделали без ошибок, то окно должно иметь
точно такой вид, как приведено ниже
Щелкните
на кнопке Form Designer 
Обратите внимание, что под формой расположена область
После создания двух объектов перейдем к созданию объекта класса - универсального
Щелкните
правой кнопкой мыши на объекте oleDbDataAdapter1 и
из контекстного меню выполните команду 
Откроется
диалоговое окно 
После
щелчка на кнопке OK будет создан объект набора данных с именем
dataSet11 (для соединения с индексом 1 можно создать несколько
наборов данных с индексами 11, 12, ...). Теперь окно Design
оболочки имеет область 
Теперь приступим к созданию средств отображения данных пользователю. Для этого используем компонент ListBox.
Перенесите
(двойным щелчком) на форму компонент ListBox из вкладки Windows
Forms панели Toolbox
В панели
Properties установите свойства компонента ListBox в соответствии
с таблицей| Свойство | Значение |
|---|---|
|
|
|
dataSet11 |
DisplayMember |
Customers.CompanyName |
ValueMember |
Customers.CustomerID |
Хоть мы и правильно связали ListBox с набором данных, но если откомпилировать и запустить форму, данных в списке не будет. Для того, чтобы они загрузились в связанный с ними список ListBox, нужно написать код C#.
Щелкните
правой кнопкой мыши в любом месте редактора Design и в появившемся
контекстном меню выберите команду View Code, чтобы перейти
в режим редактирования кода.
Через
раскрывающийся список Form1()
Вставьте
строку кода, заполняющего объект класса ListBox, как приведено
ниже..........................................................
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
oleDbDataAdapter1.Fill(dataSet11);
}
..........................................................
Постройте
проект, результат должен быть таким
Обратите внимание на код, который генерировала оболочка, пока мы манипулировали с проектом, находясь в режиме проектирования. Основная его часть спрятана в разделе
#region Windows Form Designer generated code ..................................................... #endregion
и мы, как разработчики, не должен вносить туда изменения (по возможности воздерживаться - пока)!!!
Если в таблице содержится много данных, то заполнение списка
данными, как это мы только что проделали, даже из нескольких
столбцов требует больших затрат вычислительных ресурсов. Ниже
мы применим параметризованный (с параметрами)
Предположим, что в базе данных содержатся данные о сотнях тысяч заказчиков и поэтому не следует загружать в элемент управления списком сразу всю таблицу заказчиков. Рассмотрим способы ограничения данных, отображаемых в списке.
Прежде всего необходимо сделать копию предыдущей формы. Затем
в форму нужно ввести элементы управления Label и TextBox, из
которых в оператор Select, содержащийся в элементе управления OleDbDataAdapter, будет поступать информация, позволяющая ограничить
объем данных, отображаемых в списке. В форму нужно ввести кнопку
Button, при щелчке на которой будет вызываться метод
элемента управления OleDbDataAdapter после введения новых данных
в текстовое поле.
Здесь мы чуть облегчим себе работу, чтобы заново не создавать и не настраивать элементы соединения с базой. Мы просто скопируем код предыдущей формы вместе с объектами и их настройками в новую форму. После этого достаточно будет дополнить новую форму необходимыми элементами и настроить только их.
Откройте
панель Solution Explorer и, вызвав контекстное меню для
файла Form1.cs, выполните команду Copy
Затем
щелкните правой кнопкой мыши на корневом узле текущего проекта
и выполните команду Paste контекстного меню
К проекту добавится файл с дежурным именем Copy of Form1.cs

Присвойте
вновь созданной форме имя Form2.cs и,
вызвав для этого файла контекстное меню, выполните команду
View Code , чтобы перейти в режим редактирования кода
Измените
для вновь созданной копии public class Form2 : System.Windows.Forms.Form
.......................
public Form2()
.......................
static void Main()
{
Application.Run(new Form2());
}
Перейдите
в режим Design файла Form2.cs, выделите форму и в панели
Properties измените значение свойства Text на Form2 Убедитесь,
что все помещенные ранее на первую форму элементы управления
сохранились и на второй форме, в том числе и элемент ListBox,
растянутый по всей клиентской области формы. Внутри нового
класса Form2 за ними можно оставить прежние имена,
поскольку в рамках приложения префикс Form2 делает их уникальными.
Теперь можно приступать к выполнению дальнейших этапов плана.
Начнем с перестройки параметров
Закройте
вкладки окна редактора для первой формы (чтобы не мешали
и случайно не подвернулись под горячую руку)
В подвале
формы выберите объект oleDbDataAdapter1 и
в панели Properties найдите его свойство SelectCommand.
Раскройте этот узел щелчком по значку "+"
и измените текущее значение свойства CommandText,
которое мы задавали мастеру при создании соединения, на SQL-командуSELECT CustomerID, CompanyName FROM Customers
WHERE (CompanyName LIKE ? + '%')
В применяемой здесь инструкции WHERE выполняется сравнение
значений поля CompanyName с заданным параметром, значение которого
будет передано из текстового поля элемента TextBox, еще не
помещенного нами на форму. Знак процента представляет собой
подстановочный символ, который указывает серверу, что в значении
поля должен быть выполнен поиск
В приведенном выражении отражается существенная разница в
использовании элементов управления OleDbDataAdapter и SqlDataAdapter.
Элемент управления OleDbDataAdapter предусматривает использование
операции ? для
указания места вставки передаваемого извне параметра в SQL-оператор SELECT, а для элемента управления SqlDataAdapter требуется
именованный параметр, такой как @parCustLimit. Фактическое
имя параметра зависит от конкретной программы. Приведем оба
варианта одной и той же SQL-команды
OleDbDataAdapter |
SELECT CustomerID, CompanyName FROM Customers
WHERE (CompanyName LIKE ? + '%') |
SqlDataAdapter |
SELECT CustomerID, CompanyName FROM Customers
WHERE (CompanyName LIKE @parCustLimit + '%') |
Установите
у элемента управления ListBox свойство Dock =Bottom и
освободите место верхней части формы для элементов управления Label, TextBox и Button. Поместите на форму эти три элемента
управления из вкладки Windows Forms панели Toolbox и откорректируйте
значения их свойств, как показано в таблице| Компонент | Свойство | Значение |
|---|---|---|
Label |
Text |
Клиент: |
TextAlign |
MiddleRight |
|
Size/Height |
20 |
|
TextBox |
Name |
txtCustLimit |
Text |
A (латинское!) |
|
Button |
Name |
btnLoadList |
Text |
Заполнить |
Дважды
щелкните на кнопке btnLoadList и
в создавшийся обработчик введите кодprivate void btnLoadList_Click(object sender, System.EventArgs e)
{
oleDbDataAdapter1.SelectCommand.Parameters[0].Value
= txtCustLimit.Text;
dataSet11.Clear();
oleDbDataAdapter1.Fill(dataSet11);
}
Удалите
из конструктора формы перекочевавший из предыдущей формы
код заполнения спискаpublic Form2()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
oleDbDataAdapter1.Fill(dataSet11);
}
В панели
Solution Explorer щелкните правой кнопкой мыши на файле Form1.cs и выполните команду контекстного меню Exclude From
Project (Исключить из проекта). Файл будет отключен
от проекта, но физически существовать останется. Позднее
его можно включить командой Add Existing Item![]() |
![]() |
Если первую форму не отключить от проекта, то в приложении
будут существовать две точки входа, которые определяются функциями Main(), что не допустимо.
Постройте
приложение и поэкспериментируйте с полем ввода. Первоначальный
после запуска результат должен выглядеть так
Списки являются удобным средством отображения ряда полей формы,
но иногда возникает потребность ознакомиться со значениями
других полей для конкретной записи, выделив ее в списке.Для
решения этой задачи нам необходимо расширить нашу предыдущую
форму и ввести в нее дополнительные элементы
В новый
SELECT, который будет
принимать в качестве параметра выбранный элемент списка. После
этого набор данных будет заполнен данными, а в текстовых полях
отобразятся значения полей текущей записи, полученные с использованием
рассматриваемого набора данных в качестве
Создадим копию предыдущей формы и будем работать с ней. Для
удобства переименуем
В панели
Solution Explorer сделайте копию формы Form2.cs, как это
мы делали с предыдущей формой
Отключите
файл Form2.cs от проекта, а копию переименуйте в файл Form3.cs
Для
файла Form3.cs в панели Solution Explorer вызовите контекстное
меню и выполните команду View Code, чтобы открыть файл в
режиме редактирования кода C#
Измените
в коде файла Form3.cs имена с Form2 на Form3 в
классе, конструкторе и точке входа Main(), используя окно

В панели
Solution Explorer вызовите контекстное меню для файла Form3.cs
и выполните команду View Designer (или выполните
двойной щелчок на узле этого файла), чтобы открыть файл в
режиме Design визуального проектирования
Измените
имена объектов работы с данными в соответствии с таблицей.
Это можно сделать через панель свойств, но лучше через окно
| Объект | Свойство | Старое значение | Новое значение |
|---|---|---|---|
ListBox |
Name |
listBox1 |
lstCustomers |
OleDbDataAdapter |
Name |
oleDbDataAdapter1 |
odaCustomerList |
|
Name |
dataSet11 |
dsCustomerList |
Разместите
в подвале формы элементы в хаотичном порядке затем через
контекстное меню подвала выполните команду Line Up

Перенесите
на форму двойным щелчком еще один компонент OleDbDataAdapter
из вкладки Data панели Toolbox.
Укажите
мастеру подключения 
Укажите,
что будут применяться 
Вспомните,
что SQL - регистронезависимый язык и присвойте
SELECT для использования параметра времени
выполнения по выбранному элементу списка следующего видаSELECT CustomerID, CompanyName, ContactName, ContactTitle,
Address, City, Region, PostalCode, Country, Phone, Fax
FROM Customers
WHERE (CustomerID = ?)
в окне мастера

Щелкните
на кнопке 
На последнем этапе должно появиться приведенное ниже окно, свидетельствующее об успешном подключении к базе

Список полей, участвующих в команде SELECT, можно посмотреть
в панели Server
Explorer, т.е. мы в

Переименуйте
в панели Properties созданный объект oleDbDataAdapter1 на odaCustomerIndividual
Щелкните
правой кнопкой мыши на элементе odaCustomerIndividual и
выполните команду
Создайте
новый набор данных с именем dsCustomerIndividual 
Мастер создаст набор данных, автоматически добавив к указанному имени единичку.
Отредактируйте
через панель Properties имя созданного набора данных с dsCustomerIndividual1
на dsCustomerIndividual Теперь в подвале нашей формы должны находиться два odaCustomerList и odaCustomerIndividual ) и два набора
данных ( dsCustomerList и dsCustomerIndividual ).

Теперь пришла пора модифицировать интерфейс пользователя на форме, дополнив ее необходимыми компонентами.
Отключите
свойство ListBox ( Name = lstCustomers ) списка
Освободите
место справа от списка и поместите на него элементы Label
и TextBox (лучше поместить один экземпляр, настроить его
на общие свойства, затем накопировать нужное количество ).
Для выравнивания элементов пользуйтесь панелью инструментов
Для
всех текстовых меток Label назначьте следующие
значения общих свойств: Size/Width=96; Size/Height=20;
TextAlign=MiddleRight
Для
всех текстовых полей TextBox назначьте следующие
значения общих свойств: Text=Пусто;
ReadOnly =True;
BorderStyle =FixedSingle
Индивидуальные
значения других свойств приведены в таблице Label |
TextBox | |
|---|---|---|
Text= |
Name= |
(DataBindings)/Text/dsCustomerIndividual/Customers= |
Customer ID: |
txtCustomerID |
CustomerID |
Company Name: |
txtCompanyName |
CompanyName |
: |
txtContactName |
ContactName |
: |
txtContactTitle |
ContactTitle |
Address: |
txtAddress |
Address |
City: |
txtCity |
City |
: |
txtRegion |
|
: |
txtPostalCode |
PostalCode |
Country: |
txtCountry |
Country |
: |
txtPhone |
|
: |
txtFax |
|
Значения свойств мы выбрали в соответствии с именами полей таблицы данных Customers, чтобы мозги не задымились.

После
разработки дизайна форма должна выглядеть так (студент Панасюк!
Именно так. Я "жирный" пользователь и не приму
неряшливый интерфейс. Хочешь получить зачет, а потом и 
Теперь пора приступить к разработке кода. Прежде всего откорректируем обработчик кнопки btnLoadList.
Перейдите
в режим View Code файла Form3.cs, найдите обработчик btnLoadList_Click() и откорректируйте его так// Обработчик кнопки
private void btnLoadList_Click(object sender, System.EventArgs e)
{
// Присвоить параметру адаптера данных значение,
// введенное для ограничения объема списка
odaCustomerList.SelectCommand.Parameters[0].Value
= txtCustLimit.Text;
// Удалить текущие данные в наборе данных
dsCustomerList.Clear();
// Заполнить набор данных списком заказчиков
odaCustomerList.Fill(dsCustomerList);
// Заполнить отдельный набор данных для начальной записи
RefreshIndividual();
}
// Обновление отдельного набора данных
private void RefreshIndividual()
{
// Очистить отдельный набор данных
dsCustomerIndividual.Clear();
// Определить, выбран ли текущий элемент
if(lstCustomers.SelectedIndex != -1)
{
// Присвоить параметру SQL адаптера данных отдельного
// набора выбранный идентификатор заказчика
odaCustomerIndividual.SelectCommand.Parameters[0].Value
= lstCustomers.SelectedValue;
// Заполнить набор данных
odaCustomerIndividual.Fill(dsCustomerIndividual);
}
}
Теперь осталось только создать обработчик события SelectedIndexChanged,
который будет срабатывать при каждом выделении нового элемента
списка и обновлять содержимое текстовых полей.
Перейдите
в режим Design и выделите элемент lstCustomers.
В панели Properties найдите событие SelectedIndexChanged и
двойным щелчком на поле значений создайте новый обработчик
Заполните
обработчик следующим кодом// Обработчик кнопки
private void btnLoadList_Click(object sender, System.EventArgs e)
{
// Присвоить параметру адаптера данных значение,
// введенное для ограничения объема списка
odaCustomerList.SelectCommand.Parameters[0].Value
= txtCustLimit.Text;
// Удалить текущие данные в наборе данных
dsCustomerList.Clear();
// Заполнить набор данных списком заказчиков
odaCustomerList.Fill(dsCustomerList);
// Заполнить отдельный набор данных для начальной записи
RefreshIndividual();
}
// Обновление отдельного набора данных
private void RefreshIndividual()
{
// Очистить отдельный набор данных
dsCustomerIndividual.Clear();
// Определить, выбран ли текущий элемент
if(lstCustomers.SelectedIndex != -1)
{
// Присвоить параметру SQL адаптера данных отдельного
// набора выбранный идентификатор заказчика
// Заполнить набор данных
try
{
odaCustomerIndividual.SelectCommand.Parameters[0].Value
= lstCustomers.SelectedValue;
odaCustomerIndividual.Fill(dsCustomerIndividual);
}
catch(Exception e1)
{
MessageBox.Show(e1.Message);
}
}
}
// Обработчик выбора элемента списка
private void lstCustomers_SelectedIndexChanged(object sender, System.EventArgs e)
{
// Заполнить отдельный набор данных значениями
// полей текущего элемента списка
RefreshIndividual();
}
Полный текст файла Form3.cs
Выделите
элемент TextBox текстового поля с именем txtCustLimit в
самом верху формы и присвойте его свойству Text пустое значение,
чтобы иметь возможность закачивать все содержимое таблицы Customers.
Постройте
приложение и проверьте его работоспособность. Экран должен
быть примерно таким
До сих пор мы создавали формы, позволяющие просматривать данные, но более важной задачей является обеспечение возможности для пользователя редактировать и обновлять данные в базе данных. Займемся этим.
Чтобы не терять прежние наработки, нужно создать копию формы и ее наращивать, как мы это делали в предыдущих случаях. Причем нужно иметь ввиду, что в конце выполнения этой лабораторной работы мы, возможно, создадим презентационную форму для запуска из нее любой из разработанных здесь форм. Да и промежуточные результаты иметь всегда неплохо под рукой.
Работу предыдущей формы в режиме просмотра данных будем считать естественным до тех пор, пока пользователь не пожелает начать редактирование. Для обеспечения этой возможности предусмотрим три кнопки, с помощью которых можно выполнить следующие действия:
На данном этапе мы задействуем класс BindingContext.
Этот класс упрощает работу с элементами управления, связанных
с данными. В дальнейшем можно применить также и класс BindingManagerBase,
который обеспечивает синхронизацию наборов данных с элементами
управления.
Создайте
копию предудущего файла Form3.cs и назовите его Form4.cs.
Отключите
из проекта файл Form3.cs
Замените
в коде Form4.cs все значения Form3 на Form4,
используя окно
Для
проверки постройте проект и убедитесь, что функциональность
предыдущей формы сохранилась - значит мы не сделали ошибок.
Поместите
на форму три кнопки, как показано на рисунке (свободное место
зарезервировано), и задайте им значения свойств, приведенные
в таблице| Объект | Свойство | Значение |
|---|---|---|
Button |
Name |
btnEdit |
Text |
Edit |
|
Button |
Name |
btnSave |
Text |
Save |
|
Button |
Name |
btnCancel |
Text |
|

Выполните
команду Format/
Создайте
обработчики события Click для кнопок и
заполните их так// Обработчик события Click кнопки Edit
private void btnEdit_Click(object sender, System.EventArgs e)
{
// Разрешить редактирование данных в кэше
ActivateEditing(true);
}
// Функция изменения свойств текстовых полей
private void ActivateEditing(bool bEnable)
{
// Только для чтения
txtCustomerID.ReadOnly =
txtCompanyName.ReadOnly =
txtContactName.ReadOnly =
txtContactTitle.ReadOnly =
txtAddress.ReadOnly =
txtCity.ReadOnly =
txtRegion.ReadOnly =
txtPostalCode.ReadOnly =
txtCountry.ReadOnly =
txtPhone.ReadOnly =
txtFax.ReadOnly = !bEnable;
// Стиль текстовых полей
if(bEnable)
{
txtCustomerID.BorderStyle =
txtCompanyName.BorderStyle =
txtContactName.BorderStyle =
txtContactTitle.BorderStyle =
txtAddress.BorderStyle =
txtCity.BorderStyle =
txtRegion.BorderStyle =
txtPostalCode.BorderStyle =
txtCountry.BorderStyle =
txtPhone.BorderStyle =
txtFax.BorderStyle = BorderStyle.Fixed3D;
}
else
{
txtCustomerID.BorderStyle =
txtCompanyName.BorderStyle =
txtContactName.BorderStyle =
txtContactTitle.BorderStyle =
txtAddress.BorderStyle =
txtCity.BorderStyle =
txtRegion.BorderStyle =
txtPostalCode.BorderStyle =
txtCountry.BorderStyle =
txtPhone.BorderStyle =
txtFax.BorderStyle = BorderStyle.FixedSingle;
}
}
// Обработчик события Click кнопки Save
private void btnSave_Click(object sender, System.EventArgs e)
{
SaveRecord();
ActivateEditing(false);
}
// Сохранить изменения в базе данных
private void SaveRecord()
{
// Применить класс BindingContext для завершения
// текущего сеанса редактирования, чтобы иметь
// возможность записать обновления в базу данных
this.BindingContext[dsCustomerIndividual, "Customers"].EndCurrentEdit();
// Обновить данные в кэше из набора данных dsCustomerIndividual
// в поставщик данных odaCustomerIndividual
odaCustomerIndividual.Update(dsCustomerIndividual, "Customers");
// Передать данные из кэша поставщика данных в базу
dsCustomerIndividual.AcceptChanges();
}
// Обработчик события Click кнопки Cancel
private void btnCancel_Click(object sender, System.EventArgs e)
{
// Для отмены текущей операции
// применяется класс BindingContext
this.BindingContext[dsCustomerIndividual, "Customers"].CancelCurrentEdit();
ActivateEditing(false);
}
Выделите
текстовое поле txtCustLimit и очистите в нем свойство Text,
чтобы список изначально заполнялся полностьюВспомните, что при создании объекта odaCustomerIndividual мы
настраивали мастер

При нажатии кнопки

В результате выдавалось окно с возможностями

Теперь пришла пора снять с адаптера свойство защиты изменений данных в базе!!!
В режиме
дизайна выделите в подвале формы odaCustomerIndividual и
в нижней части панели Properties щелкните по ссылке Configure
Data 
Появится мастер настройки поставщика
данных, в котором дойдите до вкладки с кнопкой

Постройте
проект и удостоверьтесь в правильной работе добавленных возможностей. При проверке добавьте пару
символов в поле Company Name, а затем сотрите их, чтобы база
соответствовала оригиналу для получения одинаковых со мной
результатов.При разработке кода функции SaveRecord() мы использовали обновление
данных в базе в два этапа: вначале сохранили изменения в поставщике
данных, и лишь потом дали команду на окончательное внесение
изменений в саму базу. Такой подход реализован в
среде
Механизм работы таков: SELECT на
Пользователь в отсоединенном режиме может
Механизм
В SQL Server наиболее распространены следующие типы проверки
нарушения
Функционирование среды

<?xml version="1.0" standalone="05_57"?>
<xs:schema id="DataSet1"
targetNamespace="http://www.tempuri.org/DataSet1.xsd"
xmlns:mstns="http://www.tempuri.org/DataSet1.xsd"
xmlns="http://www.tempuri.org/DataSet1.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
attributeFormDefault="qualified" elementFormDefault="qualified">
<xs:element name="DataSet1"
msdata:IsDataSet="true" msdata:Locale="ru-RU">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
<xs:element name="Customers">
<xs:complexType>
<xs:sequence>
<xs:element name="CustomerID" type="xs:string" />
<xs:element name="CompanyName" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
<xs:unique name="Constraint1" msdata:PrimaryKey="true">
<xs:selector xpath=".//mstns:Customers" />
<xs:field xpath="mstns:CustomerID" />
</xs:unique>
</xs:element>
</xs:schema>
Не менее важной задачей, чем редактирование данных, является
возможность добавления новых и удаления существующих записей
в таблице. Нужно поместить на форму две новых кнопки New и
Delete и ввести переменную CompanyName попадает в область данных, загруженных в список
с учетом txtCustLimit.
Создайте
копию формы файла Form4cs, переименуйте ее в файл Form5.cs
и отключите от проекта файл Form4.cs
Просмотрите
код файла Form5.cs и выполните замену слов Form4 на Form5
в поисковике оболочки.
Постройте
проект и убедитесь, что функциональность новой формы сохранилась.
Под
кнопкой btnEdit поместите две новых кнопки со значениями Name=btnNew; Text=New; Name=btnDelete; Text=Delete
Выделите
в подвале формы odaCustomerList и
внизу панели Properties щелкните по ссылке Configure
Data odaCustomerIndividual.
Создайте
для новых кнопок обработчики и заполните их, используя окончательный
для данного этапа код C#.........................................................
static void Main()
{
Application.Run(new Form5());
}
//*****************************************************************
// Переменная-член класса для контроля над тем,
// происходит ли добавление или редактирование записи
private bool mbAddNew;
//*****************************************************************
// Обработчик кнопки загрузки данных
// в список ListBox с именем lstCustomers
private void btnLoadList_Click(object sender, System.EventArgs e)
{
LoadList();
}
//*****************************************************************
// Загрузка данных в список ListBox с именем lstCustomers
private void LoadList()
{
// Присвоить параметру адаптера данных значение,
// введенное для ограничения объема списка
odaCustomerList.SelectCommand.Parameters[0].Value
= txtCustLimit.Text;
// Удалить текущие данные в наборе данных
dsCustomerList.Clear();
// Заполнить набор данных списком заказчиков
odaCustomerList.Fill(dsCustomerList);
// Заполнить отдельный набор данных для начальной записи
RefreshIndividual();
}
//*****************************************************************
// Обновление отдельного набора данных
private void RefreshIndividual()
{
// Очистить отдельный набор данных
dsCustomerIndividual.Clear();
// Определить, выбран ли текущий элемент
if(lstCustomers.SelectedIndex != -1)
{
// Присвоить параметру SQL адаптера данных отдельного
// набора выбранный идентификатор заказчика
// Заполнить набор данных
try
{
odaCustomerIndividual.SelectCommand.Parameters[0].Value
= lstCustomers.SelectedValue;
odaCustomerIndividual.Fill(dsCustomerIndividual);
}
catch(Exception e1)
{
MessageBox.Show(e1.Message);
}
}
}
//*****************************************************************
// Обработчик выбора элемента списка
private void lstCustomers_SelectedIndexChanged(object sender, System.EventArgs e)
{
// Заполнить отдельный набор данных значениями
// полей текущего элемента списка
RefreshIndividual();
}
//*****************************************************************
// Обработчик события Click кнопки Edit
private void btnEdit_Click(object sender, System.EventArgs e)
{
// Разрешить редактирование данных в кэше
ActivateEditing(true);
}
//*****************************************************************
// Функция изменения свойств текстовых полей
private void ActivateEditing(bool bEnable)
{
// Только для чтения
txtCustomerID.ReadOnly =
txtCompanyName.ReadOnly =
txtContactName.ReadOnly =
txtContactTitle.ReadOnly =
txtAddress.ReadOnly =
txtCity.ReadOnly =
txtRegion.ReadOnly =
txtPostalCode.ReadOnly =
txtCountry.ReadOnly =
txtPhone.ReadOnly =
txtFax.ReadOnly = !bEnable;
// Стиль текстовых полей
if(bEnable)
{
txtCustomerID.BorderStyle =
txtCompanyName.BorderStyle =
txtContactName.BorderStyle =
txtContactTitle.BorderStyle =
txtAddress.BorderStyle =
txtCity.BorderStyle =
txtRegion.BorderStyle =
txtPostalCode.BorderStyle =
txtCountry.BorderStyle =
txtPhone.BorderStyle =
txtFax.BorderStyle = BorderStyle.Fixed3D;
}
else
{
txtCustomerID.BorderStyle =
txtCompanyName.BorderStyle =
txtContactName.BorderStyle =
txtContactTitle.BorderStyle =
txtAddress.BorderStyle =
txtCity.BorderStyle =
txtRegion.BorderStyle =
txtPostalCode.BorderStyle =
txtCountry.BorderStyle =
txtPhone.BorderStyle =
txtFax.BorderStyle = BorderStyle.FixedSingle;
}
}
//*****************************************************************
// Обработчик события Click кнопки Save
private void btnSave_Click(object sender, System.EventArgs e)
{
SaveRecord();
ActivateEditing(false);
// Добавлен код для загруки новой записи
if(mbAddNew)
{
// Загрузка данных новой записи
LoadList(); // Наша функция
// Обновление отдельного набора данных
RefreshIndividual(); // Наша функция
mbAddNew = false;
}
}
//*****************************************************************
// Сохранить изменения в базе данных
private void SaveRecord()
{
// Применить класс BindingContext для завершения
// текущего сеанса редактирования, чтобы иметь
// возможность записать обновления в базу данных
this.BindingContext[dsCustomerIndividual, "Customers"].EndCurrentEdit();
// Обновить данные в кэше из набора данных dsCustomerIndividual
// в поставщик данных odaCustomerIndividual
odaCustomerIndividual.Update(dsCustomerIndividual, "Customers");
// Передать данные из кэша поставщика данных в базу
dsCustomerIndividual.AcceptChanges();
}
//*****************************************************************
// Обработчик события Click кнопки Cancel
private void btnCancel_Click(object sender, System.EventArgs e)
{
// Для отмены текущей операции
// применяется класс BindingContext
this.BindingContext[dsCustomerIndividual, "Customers"].CancelCurrentEdit();
ActivateEditing(false);
mbAddNew = false;
}
//*****************************************************************
private void btnNew_Click(object sender, System.EventArgs e)
{
mbAddNew = true;
// Добавить новую запись с использованием класса BindingContext
this.BindingContext[dsCustomerIndividual, "Customers"].AddNew();
ActivateEditing(true);
}
//*****************************************************************
private void btnDelete_Click(object sender, System.EventArgs e)
{
// Отменить строку для удаления с использованием
// метода RemoveAt() класса BindingContext
this.BindingContext[dsCustomerIndividual, "Customers"]
.RemoveAt(BindingContext[dsCustomerIndividual, "Customers"].Position);
// Обновить данные в кэше из набора данных dsCustomerIndividual
// в поставщик данных odaCustomerIndividual
odaCustomerIndividual.Update(dsCustomerIndividual, "Customers");
// Передать данные из кэша поставщика данных в базу
dsCustomerIndividual.AcceptChanges();
// Перезагрузить список
LoadList();
// Отобразить первую запись
RefreshIndividual();
// Отключить текстовые поля
ActivateEditing(false);
}
Постройте
проект и удостоверьтесь в правильной работе добавленных возможностей. При
проверке добавляйте строки, а затем удаляйте их, но не
трогайте существующие записи, чтобы база соответствовала
оригиналу для получения одинаковых со мной результатов.
При
анализе кода в 
Приведенный код полность рабочий, снабжен подробными комментариями, поэтому попробуйте проанализировать его самостоятельно (при необходимости для удобства можете распечатать).
В процессе эксплуатации приложений и баз данных иногда приходится сталкиваться с ошибками времени выполнения. Обычно такие ошибки называют исключениями. При работе с базами данных исключения возникают в процессе ввода данных пользователем и обновления базы данных на сервере. Их правильная обработка является важной составляющей создания надежных приложений.
Если в программе не предусмотрено применение соответствующих
средств
Исключения времени выполнения могут возникать почти в любой
части приложения. Разработчику для их управления предлагаются
конструкции языка try-catch-finally-throw (попытка-
System.Exception. Одним из таких System.Data.OleDb.OleDbException, который мы будем
ниже использовать.throw предназначен
для прямого вызова из программы catch используется для перехвата
конкретных исключений. В программе может быть предусмотрено
несколько таких блоков для обработки всех возможных исключений,
которые могут в ней возникнуть.try - это фрагмент кода, во время
выполнения которого происходит отслеживание возникающих исключений.
При возникновении исключения выполнение кода, определенного
в блоке try, прерывается, и начинает выполняться код, определенный
в ближайшем блоке цепочки блоков catch с подходящей настройкой.
Если исключение не возникло при выполнении всего блока try,
то следующие за ним блоки catch игнорируются.finaly следует в конце
блоков try/catch и выполняется
всегда, не зависимо от того, сработало исключение или нет.
Его главное назначение - гарантировать, что ресурсы, которые
открыты потенциально опасным методом, будут обязательно освобождены.
В реальных приложениях этот блок используется для освобождения
памяти, Добавим средства защиты в наше приложение, пытаясь
повысить его живучесть. Уязвимым местом в коде проекта является
операция SaveRecord().
Найдите
в коде файла Form5.cs функцииprivate void btnSave_Click(object sender, System.EventArgs e)private void SaveRecord() private void btnDelete_Click(object sender, System.EventArgs e)
Для
быстрого поиска нужных разделов кода пользуйтесь раскрывающимся
списком вверху 
Вставьте
в функции необходимый код, который приведен ниже и выделен
синим цветом.//*****************************************************************
// Обработчик события Click кнопки Save
private void btnSave_Click(object sender, System.EventArgs e)
{
// Блок обработки исключений
try
{
SaveRecord();
}
catch(Exception saveException) // Имя объекта исключения произвольное
{
MessageBox.Show("Произошла следующая ошибка:\n"
+ saveException.Message
, "\nСохранение текущих изменений отклонено!");
return;
}
ActivateEditing(false);
// Добавлен код для загруки новой записи
if(mbAddNew)
{
// Загрузка данных новой записи
LoadList(); // Наша функция
// Обновление отдельного набора данных
RefreshIndividual(); // Наша функция
mbAddNew = false;
}
}
//*****************************************************************
// Сохранить изменения в базе данных
private void SaveRecord()
{
// Блок обработки исключений
try
{
// Применить класс BindingContext для завершения
// текущего сеанса редактирования, чтобы иметь
// возможность записать обновления в базу данных
this.BindingContext[dsCustomerIndividual, "Customers"].EndCurrentEdit();
// Обновить данные в кэше из набора данных dsCustomerIndividual
// в поставщик данных odaCustomerIndividual
odaCustomerIndividual.Update(dsCustomerIndividual, "Customers");
// Передать данные из кэша поставщика данных в базу
dsCustomerIndividual.AcceptChanges();
}
catch(Exception saveException)
{
// Генерируем исключение, которое будет обработано
// во внешнем блоке try-catch, вызывающем эту функцию
throw saveException;
}
}
//*****************************************************************
private void btnDelete_Click(object sender, System.EventArgs e)
{
// Блок обработки исключений
try
{
// Отменить строку для удаления с использованием
// метода RemoveAt() класса BindingContext
this.BindingContext[dsCustomerIndividual, "Customers"]
.RemoveAt(BindingContext[dsCustomerIndividual, "Customers"].Position);
// Обновить данные в кэше из набора данных dsCustomerIndividual
// в поставщик данных odaCustomerIndividual
odaCustomerIndividual.Update(dsCustomerIndividual, "Customers");
// Передать данные из кэша поставщика данных в базу
dsCustomerIndividual.AcceptChanges();
}
catch(System.Data.OleDb.OleDbException delException)
{
// Проверяем, не относится ли возникшее исключение
// к конкретному типу 3621, которое свидетельствует
// об ошибочной попытке удалить запись, тогда как
// в другой таблице существуют связанные с ней записи
if(delException.Errors[0].NativeError == 3621)
MessageBox.Show("Призошла ошибка попытки \n удаления связанной записи!"
,"Ошибка удаления в таблице Customer"
,MessageBoxButtons.OK
,MessageBoxIcon.Exclamation);
else
MessageBox.Show("Неопознанная ошибка \n при удалении записи!"
,"Ошибка удаления в таблице Customer"
,MessageBoxButtons.OK
,MessageBoxIcon.Exclamation);
return;
}
catch(Exception delException)
{
MessageBox.Show(delException.Message
,"Ошибка удаления в таблице Customer"
,MessageBoxButtons.OK
,MessageBoxIcon.Exclamation);
return;
}
// Перезагрузить список
LoadList();
// Отобразить первую запись
RefreshIndividual();
// Отключить текстовые поля
ActivateEditing(false);
}
Запретите
в одном или обоих При попытке сохранения или удаления данных наши обработчики исключений будут выдавать примерно такие сообщения



А само приложение, при этом, будет сохранять полную работоспособность, бодрость духа и даже не кашлять.
Верните
свойства поставщиков данных изменять данные для возможности
выполнения дальнейших этапов построения проекта.В форме ввода данных должны быть предусмотрены не только основные средства обработки данных, но и учтены такие второстепенные нюансы, как возможность запретить или разрешить использование элементов управления с учетом тех операций, которые выполняются в настоящий момент с записью. Нужно своевременно включать или отключать важные кнопки, чтобы пользователь в критические дни чувствовал себя защищенным - без кариеса, угрей, дурного запаха, перхоти, жирных пятен, вредных бактерий и насекомых и т.д. и т.п.
На данном этапе наша форма обеспечивает выполнение основной части важнейших функций обработки данных. Но пользователи могут плохо ориентироваться в том, когда им разрешено выполнять определенные операции с кнопками.
В этом разделе мы реализуем следующие функции в нашем приложении:
Enabled кнопок btnSave, btnCancel, btnNew и btnDelete в
соответствующих Closing формы,
который перед завершение программы позволяет проверить, внесены
ли изменения в текущую запись, и нужно ли их в таком случае
сохранить.Начнем с того, что откорректируем две ранее созданные нами
функции RefreshIndividual() и ActivateEditing().
Затем обеспечим проверку того, была ли выбрана запись в списке
заказчиков lstCustomers.
В случае отрицательного ответа должно быть запрещено применение
двух кнопок, btnEdit и btnDelete.
Если же запись в списке заказчиков выбрана, то эти две кнопки
должны быть разрешены и обновлено содержимое текстовых полей
набором данных dsCustomerIndividual.
Разместите
в конце RefreshIndividual() и ActivateEditing() код
управления доступностью кнопок, как приведено ниже//*****************************************************************
// Обновление отдельного набора данных
private void RefreshIndividual()
{
......................................................
// Изменить свойство доступности кнопок
if(lstCustomers.SelectedIndex == -1)
{
btnEdit.Enabled = false;
btnDelete.Enabled = false;
}
else
{
btnEdit.Enabled = true;
btnDelete.Enabled = true;
}
}
//*****************************************************************
// Функция изменения свойств текстовых полей
private void ActivateEditing(bool bEnable)
{
......................................................
// Разрешить или запретить применение соответствующих кнопок
btnEdit.Enabled = !bEnable;
btnNew.Enabled = !bEnable;
btnDelete.Enabled = !bEnable;
btnCancel.Enabled = bEnable;
btnSave.Enabled = bEnable;
// Установить фокус ввода на первое текстовое поле CustomerID
if(bEnable)
txtCustomerID.Focus();
}
Разместите
внизу формы кнопку завершения работы приложения и назначьте
ей свойства Name=btnClose; Text=Close
Создайте
обработчик для кнопки btnClose и заполните
его кодом так//*****************************************************************
private void btnClose_Click(object sender, System.EventArgs e)
{
this.Close();
}
Теперь пришла пора создать обработчик события Closing формы.
В нем нужно проверить состояние кнопки btnSave в момент закрытия
приложения. Если она доступна, значит существуют несохраненные
изменения данных. В этом случае нужно спросить у пользователя,
желает ли он сохранить внесенные изменения.
Перейдите
в режим Design, откройте панель Properties и в раскрывающемся
списке установите текущим элемент формы Form5. Затем в режиме Events панели Properties найдите событие Closing и двойным
щелчком на поле значений создайте для него обработчик
Заполните
обработчик следующим кодом//*****************************************************************
private void Form5_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if(!btnSave.Enabled) return; // Ничего не надо - все сохранено!
string caption = "Сохранение результатов редактирования";
string message = "Хотели бы Вы сохранить текущие изменения?";
MessageBoxButtons buttons = MessageBoxButtons.05_57No;
DialogResult result;
// Вывести пользователю предупреждение.
result = MessageBox.Show(this, message, caption, buttons);
// Проанализировать выбор пользователя
if(result == DialogResult.No) return; // Не желает сохранять
// Пытаемся сохранить
try
{
SaveRecord();
}
catch(Exception saveException)
{
caption = "Ошибка записи данных";
message = "Произошла следующая ошибка:\n"
+ saveException.Message
+ "\nПродолжить закрытие формы?";
// Вывести пользователю предупреждение.
result = MessageBox.Show(this, message, caption, buttons);
// Проанализировать выбор пользователя
if(result == DialogResult.No)
e.Cancel = true; // Прекратить закрытие формы
// e - аргумент этого обработчика
}
}
Добавьте
в конструктор формы Form5() вызов
нашей функции начальной загрузки списка даннымиpublic Form5()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
LoadList();
}
Постройте
приложение и проверьте заложенную в нем функциональность
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.