- •1. Язык программирования c# 3
- •2. Базовые элементы .Net Framework 67
- •3. ТЕхнология .Net Remoting 144
- •Введение
- •1. Язык программирования c#
- •1.1. Платформа .Net – обзор архитектуры
- •1.2. Язык c# - общие концепции синтаксиса
- •1.3. Система типов языка c#
- •1.4. Преобразования типов
- •1.5. Идентификаторы, ключевые слова и литералы
- •1.6. Объявление переменных, полей и констант
- •1.7. Выражения и операции
- •1.8. Операторы языка c#
- •1.9. Объявление и вызов методов
- •1.10. Массивы в c#
- •1.11. Работа с символами и строками в c#
- •1.12. Синтаксис объявления класса, Поля и методы класса
- •1.13. Свойства и индексаторы
- •1.14. Конструкторы класса и Жизненный цикл объекта
- •1.15. Наследование классов
- •1.16. Перегрузка операЦий
- •1.17. Делегаты
- •1.18. События
- •1.19. Интерфейсы
- •1.20. Структуры и перечисления
- •1.21. Пространства имен
- •1.22. Генерация и обработка исключительных ситуаций
- •1.23. Нововведения в языке c# 2.0
- •1.24. Обобщенные типы (generics)
- •2. Базовые элементы .Net Framework
- •2.1. Метаданные и механизм отражения
- •2.2. Пользовательские и встроенные атрибуты
- •2.3. Пространство имен system.Collections
- •2.4. Работа с файлами и директориями
- •2.5. Использование потоков данных
- •2.6. Сериализация
- •2.7. Сериализация объектов в нестандартном формате
- •2.8. Введение в xml
- •2.9. Работа с xml-документами в .Net framework
- •2.10. МНогопоточное программирование
- •2.11. Синхронизация потоков
- •2.12. Асинхронный вызов методов
- •2.13. Состав и взаимодействие сборок
- •2.14. Конфигурирование сборок
- •3. ТЕхнология .Net Remoting
- •3.1. Домены приложений
- •3.2. Архитектура .Net Remoting
- •3.3. Активация удаленных объектов и их время жизни
- •3.4. Программная настройка Remoting
- •3.5. Удаленные Объекты с клиентской активацией
- •3.6. Настройка Remoting при помощи конфигурационных файлов
- •3.7. Хостинг распределенных приложений
- •3.8. Объекты-сообщения
- •3.9. Пользовательские канальные приемники
- •4.1. Архитектура ado.Net
- •4.2. Учебная база cd Rent
- •4.3. Соединение с базой данных
- •4.4. Выполнение команд и запросов к базе данных
- •4.5. Чтение данных и объект DataReader
- •4.6. Параметризированные запросы
- •4.7. Рассоединенный набор данных
- •4.8. Заполнение Рассоединенного набора данных
- •4.9. Объект класса DataColumn – колонка таблицы
- •4.10. Объекты класса DataRow – строки таблицы
- •4.11. Работа с объектом класса DataTable
- •4.12. DataSet и схема рассоединенного набора данных
- •4.13. Типизированные DataSet
- •4.14. Поиск и фильтрация данных в DataSet
- •4.15. Класс DataView
- •4.16. СиНхронизация набора данных и базы
- •5.1. Архитектура и общие концепции asp.Net
- •5.2. Пример aspx-страницы. Структура страницы
- •5.3. Директивы страницы
- •5.4. Класс System.Web.Ui.Page. События страницы
- •5.5. Серверные элементы управления
- •5.6. Элементы управления Web Controls
- •5.7. Проверочные элементы управления
- •5.8. Списковые элементы управления
- •5.9. Связывание данных
- •5.11. Управление состояниями в web-приложениях
- •5.12. Кэширование
- •5.13. Безопасность в web-приложениях
- •5.14. Создание пользовательских элементов управления
- •Литература
4.16. СиНхронизация набора данных и базы
Пусть в набор данных заносится информация из БД при помощи адаптера:
SqlDataAdapter da = new SqlDataAdapter(. . .);
DataSet CD_Rent = new DataSet("CD_Rent");
da.Fill(CD_Rent, "Artists");
Для переноса изменений из набора в базу используется метод адаптера Update(). Данный метод обновляет в базе одну таблицу набора (всегда!), которая, как правило, задается через параметр метода. Однако попытка выполнения следующего кода вызовет исключительную ситуацию:
CD_Rent.Tables["Artists"].Rows[3]["name"] = "Alex";
da.Update(CD_Rent, "Artists");
System.InvalidOperationException: Update requires a valid
UpdateCommand when passed DataRow collection with modified rows.
Дело в том, что при создании адаптера формируется только SelectCommand – команда для выборки данных. Остальные свойства-команды адаптера не инициализированы.
Программист может настроить необходимые команды вручную. Вначале рассмотрим SQL-синтаксис возможных команд для обновления информации в нашем примере:
INSERT INTO Artists(id ,name) VALUES (@p1, @p2)
DELETE FROM Artists WHERE (id = @p1) AND (name = @p2)
UPDATE Artists SET id = @p1, name= @p2
WHERE (id= @p3) AND (name= @p4)
В принципе, этот текст можно скопировать в свойство CommandText команд, которые будут созданы. Отдельного пояснения требует настройка параметров. Параметр, кроме установки таких свойств как имя и тип, должен быть связан со столбцом таблицы из набора данных, а в случае с командой UPDATE – еще и с определенной версией информации в столбце. Для этого используются свойства параметра SourceColumn и SourceVersion. Приведем полный текст создания и настройки команд:
// Создали соединение, которое будут использовать наши команды
SqlConnection con = new SqlConnection(. . .);
// Создали три объекта-команды
SqlCommand ins_cmd = con.CreateCommand();
SqlCommand del_cmd = con.CreateCommand();
SqlCommand upd_cmd = con.CreateCommand();
// Настраиваем текст команд
ins_cmd.CommandText = "INSERT INTO Artists(id,name) VALUES (@p1,@p2)";
del_cmd.CommandText = "DELETE FROM Artists" +
"WHERE (id=@p1) AND (name=@p2)";
upd_cmd.CommandText = "UPDATE Artists SET id=@p1, name= @p2" +
"WHERE (id= @p3) AND (name= @p4)";
// Займемся параметрами
// Создадим два параметра и поместим их в коллекцию
ins_cmd.Parameters.Add("@p1", DbType.Int32);
ins_cmd.Parameters.Add("@p2", DbType.String);
// Дополнительная настройка – укажем столбец, из которого
// берется значение параметра
ins_cmd.Parameters[0].SourceColumn = "id";
ins_cmd.Parameters[1].SourceColumn = "name";
// В случае с командой удаления – аналогичные действия
del_cmd.Parameters.Add("@p1", DbType.Int32);
del_cmd.Parameters.Add("@p2", DbType.String);
del_cmd.Parameters[0].SourceColumn = "id";
del_cmd.Parameters[1].SourceColumn = "name";
// Для команды обновления число параметров в два раза больше
upd_cmd.Parameters.Add("@p1", DbType.Int32);
upd_cmd.Parameters.Add("@p2", DbType.String);
upd_cmd.Parameters.Add("@p3", DbType.Int32);
upd_cmd.Parameters.Add("@p4", DbType.String);
upd_cmd.Parameters[0].SourceColumn = "id";
upd_cmd.Parameters[1].SourceColumn = "name";
upd_cmd.Parameters[2].SourceColumn = "id";
upd_cmd.Parameters[3].SourceColumn = "name";
// Требуется настройка – указать версию поля таблицы
upd_cmd.Parameters[2].SourceVersion = DataRowVersion.Original;
upd_cmd.Parameters[3].SourceVersion = DataRowVersion.Original;
// Помещаем наши команды в адаптер
da.InsertCommand = ins_cmd;
da.DeleteCommand = del_cmd;
da.UpdateCommand = upd_cmd;
После того, как в адаптере определены все команды, можно свободно изменять данные в рассоединенном наборе, а затем обновить их в базе вызовом Update():
DataTable dt = CD_Rent.Tables["Artists"];
DataRow row = dt.NewRow();
row["id"] = 100;
row["name"] = "Uma Thurman";
dt.Rows.Add(row);
row = dt.Rows[1];
row["name"] = "Alex";
da.Update(CD_Rent, "Artists");
Как показывает пример, ручное создание команд для адаптера даже в случае простого набора данных выглядит громоздким (хотя это очень гибкое решение). ADO.NET предоставляет класс для автоматической генерации команд адаптера. Это класс CommandBuilder (класс зависит от поставщика данных, поэтому приведено его «обобщенное» имя).
Работа с классом CommandBuilder происходит следующим образом. Создается объект класса и связывается с определенным адаптером данных, у которого уже задана команда SelectCommand. После установки подобной связи CommandBuilder отслеживает событие обновления строки данных, которое происходит при вызове метода Update(), и генерирует и выполняет необходимые SQL-команды на основе текста команды SELECT.
Приведем пример кода, использующего CommandBuilder. Вот как могла бы выглядеть «генерация» команд для адаптера, с которым мы работали:
// Создаем объект CommandBuilder и связываем его с адаптером
SqlCommandBuilder cb = new SqlCommandBuilder(da);
// И, собственно, все! Можем работать с методом Update()
. . .
da.Update(CD_Rent, "Artists");
Конечно, класс CommandBuilder не «всемогущ». Он генерирует правильные команды обновления, если выполняются все следующие условия:
запрос возвращает данные только из одной таблицы;
на таблице в базе определен первичный ключ;
первичный ключ есть в результатах вашего запроса.
Кроме этого, объект CommandBuilder не предоставляет максимальной производительности периода времени выполнения. Вы можете написать и добавить в код собственную логику обновления за время, меньшее, чем объекту CommandBuilder потребуется, чтобы выбрать и обработать необходимые для создания аналогичного кода метаданные таблицы из БД. CommandBuilder не позволяет управлять генерацией логики. Нельзя указать нужный способ оптимистического управления параллелизмом. Нельзя передавать обновления средствами хранимых процедур.
В таблице 36 приведены свойства и методы класса SqlCommandBuilder.
Таблица 36
Свойства и методы класса SqlCommandBuilder
Имя свойства или метода |
Описание |
DataAdapter |
Свойство позволяет просмотреть или изменить объект DataAdapter, сопоставленный с объектом CommandBuilder. Значение этого свойства можно задать в конструкторе объекта CommandBuilder |
DeriveParameters() |
Статический метод. Получает в качестве параметра объект-команду для вызова хранимой процедуры. На основании информации из БД, заполняет коллекцию Parameters команды-параметра |
GetDeleteCommand() |
Возвращает объект Command с логикой для свойства DeleteCommand объекта DataAdapter |
GetInsertCommand() |
Возвращает объект Command с логикой для свойства InsertCommand объекта DataAdapter |
GetUpdateCommand() |
Возвращает объект Command с логикой для свойства UpdateCommand объекта DataAdapter |
QuotePrefix |
Содержит префикс, используемый CommandBuilder для имен таблиц и столбцов в генерируемых им запросах |
QuoteSuffix |
Содержит суффикс, используемый CommandBuilder для имен таблиц и столбцов в генерируемых им запросах |
RefreshScbema() |
Указывает объекту CommandBuilder создать логику обновления заново |
5. ASP.NET