WWW.DISSERS.RU

БЕСПЛАТНАЯ ЭЛЕКТРОННАЯ БИБЛИОТЕКА

   Добро пожаловать!

Pages:     | 1 | 2 || 4 | 5 |   ...   | 8 |

«David Sceppa Microsoft Press Дэвид Москва 2003 Р Г Г If Р F г V А Л А Ц л г УДК 004.45 32.973.26-018.2 С28 Д. ...»

-- [ Страница 3 ] --

DataSet ds = new Дважды вызывая метод вы указываете объекту DataAdapter дважды выпол нить заданный запрос и дважды поместить его результаты в объект DataSet. При 146 Часть II Подключаемся: использование поставщика данных вызове метода в объекте DataSet создается таблица При втором метода Fill результаты запроса копируются в эту же таблицу объекта DataSet, Таким образом, в объекте DataSet будет по две записи о каждом клиенте.

Данный фрагмент кода не позволяет объекту узнать, что имеется две записи об одном клиенте. Обычно администраторы БД опреде ляют на таблицах БД ключи. Одно из преимуществ подобной практи ки — невозможность идентичных записей. У объекта имеется свойство Если у объектом объекта DataTable есть ключ, DataAdapter на его основе выявляет идентичные записи.

Подробнее о задании значения свойства PrimatyKey объекта DataTable — в разделе «Выборка информации схемы» этой главы, а также в разделе главы 6, посвященном этому свойству, к нашему примеру. Если перед повторным вызовом метода DataAdap на таблице Customers объекта DataSet первичный ключ, объект DataAdapter выявит идентичные записи и отбросит старые значения.

Предположим, например, что в изменились имя и телефон клиента. При повторном вызове метод Fill получит эти новые сведения. Объект DataAdapter с помощью первичного ключа объекта DataTable присутствует ли в таб лице запись о данном клиенте. да, она и DataAdapter доба в объект новую информацию. Тем не менее удаленные из БД запи си из объекта DataTable удаляются.

Представьте, что при первом вызове метода в БД присутство вала запись о клиенте, долгое время не платившем по и DataAdapter доба вил ее объект DataTable. Позже кто-то осознал данный факт и удалил соответ ствующую запись из БД. Когда вы второй раз обратитесь к объекту DataAdapter, он не найдет записи об этом клиенте в результатах запроса, но, тем не менее, не удалит эту запись объекта DataTable.

И мы опять возвращаемся в исходную точку. Чтобы обновить все данные, очи стите объект DataSet или DataTable и повторно вызовите метод Fill объекта Data Adapter. Это позволит исключить идентичные записи (даже если на таблице не определен первичный ключ), а также удалить из объекта DataSet записи, отсут ствующие в БД.

Сопоставление результатов запроса объекту DataSet Ранее я уже рассказывал о роли объекта DataAdapter. Сей час я остановлюсь на том. как использовать этот набор в коде.

Набор TableMappings объекта DataAdapter Набор как DataAdapter сопоставляет объект DataSet с вашей БД. Если вы оставите набор TableMappings объекта DataAdapter пустым и вызовете метод Fill, передав ему в качестве параметра объект DataSet и не указав имя DataAdapter решит, что вам нужен объект DataTable с именем Свойство TableMappings возвращает объект содер жащий набор объектов Следующая строка кода в набор TableMappings объект указывая DataAdapter, что он дол жен взаимодействовать с объектом DataTable Employees:

ГЛАВА 5 данных с помощью Создав объект можно создавать сопоставления со столбцами таблицы. В одном из предыдущих примеров мы посредством следующего кода сопоставляли столбцы и БД столбцам и FirstName объекта Visual Basic Dim da As объект DataAdapter Dim TblMap As Dim ColMap As = "Employees") ColMap = "EmployeelD") ColMap = "LastName") ColMap = "FirstName") Visual C# da;

объект DataAdapter DataTableMapping TblMap;

ColMap;

TblMap = ColMap = ColMap = ColMap = У объектов и есть ме позволяющий добавить набор группу сопоставлений посредством одного вызова:

Visual Basic Dim da As New объект DataAdapter Dim TblMap As DataTableMapping Dim ColMapArray As ТЫНар = "Employees") ColMapArray = New DataColumnMappingO _ "EmployeelD"), _ New "LastName"), New Visual da = new объект DataAdapter DataTableMapping TblMap;

ColMapArray;

TblMap = 148 Часть II Подключаемся: поставщика данных = new Свойство MissingMappingAction Вы уже знаете, как заполнить набор объекта информа цией о таблицах и столбцах. Но, как вы, возможно, заметили, предоставлять эту информацию не требуется. Примеры из предыдущих разделов с помощью ме тода создавали и заполняли новые объекты DataTable несмотря на то, что у объекта не было сведений о сопоставлении столбцов.

В большинстве случаев программисты используют в объекте DataSet те же имена что и в БД. Команда разработчиков ADO.NET сделала разумное предпо что программистам не понравится, если для выборки данных в объект DataSet придется в обязательном порядке заполнить набор TableMappings объек та DataAdapter идентичными именами столбцов БД и объекта DataSet. Если при просмотре результатов запроса объект DataAdapter обнаружит столбец, отсутству ющий в наборе TableMappings, он проверит значение свойства и определит, что делать с такими столбцами дальше.

MissingMappingAction принимает значения из одноименного перечис ления, относящегося к пространству имен Значение данного свойства по умолчанию — При этом объект DataAdapter сопоставляет столб цы набора результатов, отсутствующие в наборе с одноименными столбцами объекта DataSet. Если задать свойству MissingMappingAction значение DataAdapter игнорирует столбцы, отсутствующие в наборе TableMappings.

Кроме того, свойству MissingMappingAction можно задать значение Error, и в ре зультате объект DataAdapter, обнаружив отсутствующий в наборе TableMappings столбец, будет генерировать исключение.

Работа с пакетными запросами Запросы из разделов главы возвращали только один набор резуль татов. Некоторые БД, например SQL Server, позволяют выполнять пакет ные запросы, возвращающие несколько результатов:

SELECT Phone FROM Customers WHERE = SELECT CustomerlD, EmployeelD, OrderDate FROM Orders WHERE CustomerlD = Если вы создадите объект использующий этот запрос, и вставите его результаты в объект DataSet посредством такого фрагмента кода будут заполнены два объекта DataTable, относящиеся к объекту DataSet. Резуль таты первой части запроса, выполняемой к таблице Customers, помещаются в объект DataTable с именем а результаты второй выполняемой к таблице ГЛАВА 5 Получение данных с помощью объектов DataAdapter Orders, — в объект с именем 1. Вполне вероятно, что вы захотите задать объектам DataTable более содержательные имена.

Набор TableMappings объекта способен содержать несколько объек тов Добавляя записи в этот набор, можно управлять именами таблиц, которые объект использует при размещении результатов па кетного запроса. Следующий фрагмент кода помещает результаты пакетного за проса в две таблицы объекта — Customers и Orders.

Visual Basic Dim strConn, As String = & "Initial strSQL = "SELECT ContactName, Phone & _ "FROM Customers WHERE CustomerlD = & _ "SELECT CustomerlD, & _ "FROM Orders WHERE CustomerlD = Dim da As New strConn) da, "Customers") da.

Dim ds As New Visual C# string strConn, strSQL;

strConn = + "Initial strSQL = "SELECT CustomerlD, CompanyName, ContactName, Phone + "FROM Customers WHERE CustomerlD = + "SELECT OrderlD, CustomerlD, EmployeelD, OrderDate + "FROM Orders WHERE CustomerlD = OleDbDataAdapter da = new strConn);

DataSet ds = new Получение результатов выполнения хранимых процедур Объект DataAdapter позволяет поместить возвращаемые хранимой про цедурой, в объект DataSet или DataTable. Предположим, у вас есть такое опреде ление хранимой процедуры:

CREATE PROCEDURE AS SELECT CustomerlD, ContactName, Phone Customers RETURN Следующие запросы позволяют поместить возвращаемые этой процедурой результаты в объект Часть II Подключаемся;

использование поставщика данных — или — EXEC Кроме объект может на объекте Command, свойству которого задано Подробнее об использовании объектов свойства которых отличается от значения по умолчанию, — в разделе главы посвященном этому свойству.

Хранимые процедуры Oracle В отличие от хранимых SQL Server, хранимые процедуры спо собны возвращать данные только посредством параметров вывода. Тем не менее поставщик Microsoft OLE DB Provider for Oracle и драйвер Microsoft ODBC Driver for Oracle позволяют вызывать хранимые процедуры Oracle и выбирать результа ты через параметры вывода. Эта возможность описана во многих стать ях Базы знаний Синтаксис для хранимых процедур Oracle таков:

(?, 20, })} Выборка информации схемы Назначение объекта DataTable, подробно обсуждаемого в последующих разделах этой главы, — обеспечить соблюдение ограничений, определенных для данных (например, PRIMARY KEY, максимальная длина полей со строковыми типами дан ных и значений Выборка такой информации в период вы полнения связана с определенными так что объект по умолчанию ее не получает. Однако если в определенной ситуации вам потребу ется допустить падение производительности и получить информацию схемы о возвращаемых результатах, объект DataAdapter вам пару полезных функций — свойство MissingSchemaAction и метод (да, я знаю, что это ужасный каламбур).

Свойство MissingSchemaAction Как вы, вероятно, заметили, во всех примерах с методом fill исполь зуются объекты и DataTable, не содержащие информации схемы. По умол чанию объект DataAdapter при записи результатов запроса добавляет в объекты DataSet и DataTable отсутствующие столбцы. Поведением объекта DataAdapter в таких управляет свойство MissingSchemaAction.

Свойство MissingSchemaAction принимает значения из одноименного ления, относящегося к пространству имен Значение данного свойства по умолчанию — Add. Как и в случае со свойством свойству MissingSchemaAction разрешается задать значение Ignore и игнорировать ющие столбы. Кроме того, возможно значение Error, при котором объект DataA. отсутствующий столбец, генерирует исключение.

ГЛАВА 5 Получение данных с помощью объектов DataAdapter В перечислении есть еще одно значение, имя которого может ввести вас в заблуждение. При таком значении свойства SchemaAction объект обнаружив столбец, добавит его в объект DataSet или DataTable и задаст два дополнительных атрибута схемы, свя занных с этим свойством: MaxLengtb и Если объект DataTable не су ществует или не содержит столбцов, при данном значении свойства MissingSchema Action объект DataAdapter также запросит БД на предмет сведений о первичном ключе, Метод Объект предоставляет метод позволяющий выбрать в объект DataSet или DataTable только информацию схемы. Сигнатуры метода аналогичны основным сигнатурам метода Fill. Метод принимает объект DataSet, DataTable или объект DataSet и имя таблицы.

У метода также есть обязательный параметр ScbemaType, возможные значения которого — Mapped и Source. Это значение определяет, применит ли объект DataAdapter параметры своего набора TableMappings к результатам запро са или нет. Если при вызове метода FillSchema вы передали в качестве параметра ScbemaType значение будет использовать имена столбцов, воз вращенные запросом. При значении Mapped объект DataAdapter применяет к воз вращаемым запросом столбцам параметры своего набора TableMappings.

Если по сведениям БД столбец или группа столбцов являются первичным или уникальным ключом, метод задает для них значения свойств и MaxLengtb и создает в итоговом объекте DataTable первич ный ключ, Создание объектов DataAdapter в Visual Studio Теперь, когда вы узнали об основных возможностях объектов пого ворим о том, как Visual Studio позволяет ускорить создание таких объектов в приложениях, Перетаскивание объекта DataAdapter с панели На вкладке Data панели инструментов Visual Studio имеются элементы DataAdapter и SqlDataAdapter. Если перетащить любой из них в область проекти рования (рис. 5-3), панели компонентов этой области появится новый объект DataAdapter. Кроме того, запустится мастер Data Adapter Configuration Использование мастера Data Adapter Configuration Wizard Мастер Data Adapter Configuration Wizard среды Visual Studio позволяет кон фигурировать объекты DataAdapter без написания какого-либо кода.

Запустив мастер и щелкнув ОК в первом окне, вы увидите окно для настройки подключения к БД. Оно (рис. 5-4) аналогично окну Choose Connection мастера Data Form Wizard: содержит список имеющихся подключений и Часть II Подключаемся: использование поставщика данных № Bow ftojKt Рис. 5-3. Перетаскивание объекта в область проектирования ляет создавать новые. Если вы работаете с в этом окне пере числены все доступные в Server Explorer подключения к данным. При работе с доступны только подключения, добавленные с OLE SQL Server. Выберите нужное подключение к БД и щелкните чтобы перейти к следующему окну мастера.

Choose Data execute queries to load : • Che data me?

Рис. 5-4. Выбор подключения для объекта Далее мастер предлагает вам указать тип запроса — это может быть SQL-опе ратор (например, SELECT FROM Customers) или хра нимая процедура. Мастер Data Adapter Configuration Wizard даже позволяет созда вать хранимые процедуры на основании введенного вами запроса. Сейчас я по знакомлю вас с простейшим случаем — использованием SQL-оператора. Подроб ГЛАВА 5 Получение данных с помощью объектов нее о применении в объекте хранимых процедур — в главе 10, по священной обновлению БД. Щелкните Use SQL Statements (рис. 5-5) и затем — Nest.

the Г stared Рис. Указание типа запроса для объекта DataAdapter В следующем окне мастера отображается текстовое поле для ввода запроса (рис, 5-6). Кроме того, вам указать дополнительные параметры обнов ления БД. Подробнее о них — в главе 10.

Generate the the bad Рис. 5-6. Ввод запроса Щелкнув кнопку Query Builder, вы запустите мастер Query Builder, предостав ляющий простой интерфейс для создания запросов, аналогичный интерфейсу Microsoft Access. Мастер Query Builder полезен, если вы не совсем уверены, какой именно запрос нужен для объекта DataAdapter. При запуске мастера Query Builder открывается диалоговое окно 5-7) со списком доступных таблиц, представлений и функций БД.

Мастер Query облегчает выбор возвращаемых запросом таблиц и по лей, позволяет определить критерий поиска и указать порядок сортировки, а также выполнить запрос и просмотреть его результаты. Для реализации последней воз Часть II Подключаемся: использование поставщика данных следует щелкнуть в одной из панелей правой кнопкой и выбрать Run.

На рис. показаны основные возможности Query Builder. Щелкнув любой стол бец в верхней панели, вы добавите их в результаты запроса. Во второй панели можно указать критерий и порядок сортировки. Если вы привыкли писать SQL запросы воспользуйтесь третьей Изменения в одной панели отображаются в двух остальных.

Рис. 5-7. Диалоговое окно Add Table мастера Query Paula Old '. The Liu • Great. Head Gaum USA.., •.

Рис. 5-8. Создание запроса средствами мастера Query Builder ГЛАВА 5 Получение данных с помощью объектов Создав запрос, щелкните ОК. Мастер Query Builder вернет строку запроса, ко торая будет использоваться мастером Data Adapter Configuration Wizard. После того как вы щелкнете Next, мастер на основе введенного запроса и параметров под ключения сгенерирует новый объект DataAdapter. На рис. 5-9 показаны результа ты работы мастера Data Adapter Configuration Wizard tiacemert.

Рис. 5-9. Результаты работы мастера Data Adapter Configuration Чтобы сконфигурировать объект DataAdapter, мастеру требуется получить из БД такие метаданные, как имена таблиц, столбцов и сведения о первичном клю че. Если мастеру не удается сгенерировать логику ваш запрос ссылается на несколько таблиц, не имеет первичного ключа или БД не возвраща ет метаданные, в окне результатов мастер сообщит о невозможности создания объекта Создав объект средствами мастера, можно выбрать его в панели компонентов области проектирования и просмотреть его в окне Properties (рис. 5-10). Введенный в мастере запрос содержится в свойстве объек та указанного в свойсгве объекта DataAdapter.

Мастер Data Adapter Configuration Wziard годится даже для готовых объектов DataAdapter, Чтобы изменить параметры объекта DataAdapter средствами масте ра, выберите его в панели компонентов области проектирования и затем щелк ните ссылку Configure Data Adapter в нижней части окна Properties.

Перетаскивание из Server Explorer Объекты DataAdapter можно также создавать, перетаскивая таблицу или представ ление из Server Explorer в область проектирования. Если вы имеете дело с БД, таб лицы которой содержат мало такое решение окажется весьма полезным для создания объектов DataAdapter в период разработки. Тем не менее следует сколько данных будет выбирать объект DataAdapter при создании при ложения, особенно если размер БД непрерывно увеличивается.

Для записей, получаемых при перетаскивании из Server нельзя фильтр, однако вы можете столбцы, которые следует включить в запрос объекта выбрав в Server Explorer конкретные столбцы таблицы или 156 Часть II Подключаемся: использование поставщика данных Рис. 5-Ю. Просмотр свойств нового объекта представления (рис. 5-11). Чтобы выбрать несколько столбцов, удерживайте на жатой Ctrl.

Рис. 5-11. Выбор столбцов таблицы для объекта DataAdapter ГЛАВА 5 Получение данных с помощью объектов Предварительный просмотр результатов, возвращаемых объектом DataAdapter Обычно я не прибегаю к Query Builder и ввожу запрос вручную. Годы программи рования помогли мне узнать многое о себе. я упрям (это объясняет, почему иногда я насмехаюсь над мастерами и почему я по-прежнему верю, что именно этот год станет годом команды Red Sox);

кроме я — не самый бе зупречный в мире наборщик текста. Поэтому введенные мной вручную запросы не всегда как мне нужно. При этом я запускаю запрос в утилите для выполнения запросов и просматриваю результаты, пытаясь опре делить, где же ошибка. В этой ситуации Query Builder пригодится и вам, однако есть и более простой способ просмотреть период выполнения данные, возвра щаемые объектом DataAdapter.

Когда вы выбираете в панели компонентов области проектирования объект DataAdapter, в нижней части окна Properties появляется ссылка Preview Data.

кнув ее, вы увидите диалоговое окно Data Adapter Preview (рис. 5-12). Чтобы про смотреть возвращаемые объектом DataAdapter данные, щелкните Fill Dataset.

Wong Elgin Portland The Portland N 5 San Clover Karl Steel Рис. 5-12. Предварительный просмотр данных, возвращаемых объектом DataAdapter Просмотр кода, генерируемого мастером Настоятельно рекомендую вам просматривать генерируемый мастером код. Нельзя сказать, что он всегда прост для чтения или эффективен, но зато это простейший способ узнать, как взаимодействуют различные объекты в модели Изу чая главы, посвященные объектам DataAdapter, Command и Parameter, просмат ривайте генерируемый мастером Data Adapter Configuration Wizard код, чтобы закрепить теоретические знания.

Часть II Подключаемся: использование поставщика данных Генерируемый мастером код содержится в ва шего компонента, которая находится в скрытой области кода, генерируемого конструктором.

Особенности объекта DataAdapter Объект DataAdapter предоставляет свойства, методы и события на все случаи жизни.

Сейчас я о них и расскажу.

Свойства объекта DataAdapter Свойства объекта можно разделить на две группы — управляющие связью с хранилищем данных и управляющие связью с объектом Свойства первой группы — и — содержат объекты используемые объектом Data Adapter для обмена данными между хранилищем и объектом DataSet, например для передачи записей в объект DataSet или передачи изменений из объекта DataSet в БД. В табл. 5-1 описаны все свойства объекта DataAdapter.

Таблица Свойства объекта Свойство Тип данных Описание Boolean Управляет значением свойства записей, возвращаемых объектом DataAdapter (значение по умолчанию — True) Boolean продолжит ли объект DataAdapter передавать изменения при возникновении ошибки (значе ние по умолчанию — False) Используется для передачи отло женных удалений InsertCommand OleDbCommand Используется для передачи отло женных вставок Определяет действия объекта DataAdapter при обнаружении стол отсутствующих в наборе TableMappings (значение по умолча нию — Определяет действия объекта DataAdapter при обнаружении стол бцов, в наборе Columns объекта DataTable ние по умолчанию — Add) SelectCommand OleDbCommand Используется для выполнения за просов к БД и вставки результатов в объект DataSet или DataTable TableMappings Набор сведений, применяемых объектом DataAdapter для сопостав ления результатов запроса с объек тами DataSet OleDbCommand Требуется для передачи отложен ных обновлений ГЛАВА 5 Получение данных с помощью объектов DataAdapter Свойства Selectcommand, и Каждое из этих объекта DataAdapter содержит объект Command. Конкрет ный тип объекта зависит от используемого поставщика данных Так, свой ство Selectcommand объекта содержит объект а одноименное свойство объекта — объект (подроб нее об объекте Command — в главе 4).

Если в конструкторе строка запроса, она станет значени ем свойства объекта указанного в свойстве Selectcommand DataAdapter. Если вместо строки запроса передать объект Command, свяжет его со свойством объекта Если конструктору DataAdapter передан объект он будет назначен одноименному свойству объекта Command, указанного в свойстве SelectCommand объекта Если конструктору передана строка создаст новый объект Connection, задаст его свойству переданную вами и затем назначит новый объект Connection одноименному свойству объекта Command, указанного в свойстве SelectCommand объекта DataAdapter.

Свойство Ранее я уже рассказывал, что объекты DataAdapter и DataSet никак не связаны между собой в модели ADO.NET. Так как же DataAdapter узнает порядок взаимодействия с методы Update объектов OleDbDataAdapter и SqlDataAdapter принимают в качестве параметра объект DataSet. Что, если этот объект содержит несколько объектов DataTable? Как DataAdapter определит, какой объект просмотреть?

У класса DataAdapter есть свойство содержащее набор объектов Объекты обладают свойством pings, возвращающим набор объектов Эта иерархия объек тов соответствует набору объектов DataTable и в объекте DataSet.

Получая из хранилища, объект DataAdapter на основе информации из набора TableMappings определяет, в какую таблицу объекта DataSet поместить результаты запроса. Вообще говоря, при получении результатов запроса SELECT CompanyName, Phone FROM Customers вы наверняка захотите создать объект DataTable с именем Customers, содержа щий объекты DataColumn, имена которых соответствуют именам столбцов из результатов запроса. Если требуется задать объекту DataTable или объектам Data Column альтернативные имена, добавьте необходимую информацию в набор объекта DataAdapter.

Следующий фрагмент заполняет набор TableMappings объекта основываясь на запросе. Для каждого объекта TableMapping и первая строка соответствует имени элемента, получаемого объектом DataAdapter из БД, а вторая — имени элемента в объекте DataSet.

Visual Basic Dim strConn As String = "SELECT CompanyName, ContactName, Phone FROM Customers" 160 Часть II Подключаемся: использование поставщика данных = & _ "Initial Dim da As strConn) With End With C# string strConn;

"SELECT CustomerlD, CompanyName, ContactName, Phone FROM Customers";

strConn = + "Initial OleDbDataAdapter da = new strConn);

DataColumnMappingCollection cm = Можно также воспользоваться методом объекта или и добавить в набор группу элементов один вызов:

Visual Basic Dim cm As = _ New _ New "ContactName"), _ New Visual C# DataColumnMappingCollection cm = new new А что, если выполняемый объектом запрос содержит информацию об одной из таблиц объекта отсутствующую в наборе TableMappings? По умолчанию DataAdapter предполагает, что вам требуется получить эту информа цию и записать ее в таблицу. Фактически можно выполнить такой код:

ГЛАВА 5 Получение данных с помощью объектов Visual Basic Dim As String = "SELECT Phone FROM Customers" strConn = & "Initial da As New 01eDbDataAdapter(strSQL, strConn) ds As New DataSet C# string strSQL, strSQL = "SELECT CompanyName, ContactName, Phone FROM Customers";

strConn = + "Initial OleDbDataAdapter da = new strConn);

DataSet ds = new DataSet;

Свойства MissingMappingAction и Заметьте: мы не заполняли набор TableMappings объекта На самом деле мы даже не создавали таблицу в объекте DataSet;

это автоматически делал объект DataAdapter.

Выбирая результаты запроса, объект DataAdapter ищет в своем наборе Table Mappings соответствующие таблицы и столбцы. Свойство MissingMappingAction что предпримет DataAdapter получении таблиц или стол бцов, в наборе TableMappings. Значение данного свойства по умол чанию — ему можно также задавать и другие значения из перечисле ния относящегося к пространству имен Если значение свойства MissingMappingAction — Ignore, DataAdapter игнорирует столб цы и таблицы, отсутствующие в наборе TableMappings. Кроме того, MappingAction можно задать значение Error, и в результате объект об наружив отсутствующий в наборе TableMappings столбец, сгенерирует исключение.

Объект DataAdapter также обладает MissingSchemaAction, которое оп ределяет, что произойдет, если возвращенные запросом столбцы или таблицы отсутствуют в конечном объекте DataSet. Значение данного свойства по умолча нию — при этом DataAdapter добавляет отсутствующие таблицы и столбцы DataSet. можно задавать любые значения из одноимен ного перечисления, относящегося к пространству имен — Error. Если значение свойства MissingSchemaAction — Ignore, DataAdapter игнорирует столбцы и таблицы, отсутствующие в объекте DataSet. При значении Error объект DataAdapter, обнаружив в объекте DataSet столбец, сгенерирует исключение.

Если значение свойства MissingSchemaAction — объект добавит в объект DataSet отсутствующие таблицы и поля, а также сведения ключа 162 Часть Подключаемся: использование поставщика данных для таблиц. Такое поведение аналогично вызову метода объекта Data подробнее о котором — чуть ниже.

Свойство Работая в службе поддержки и помогая разработчикам решать проблемы с ADO, я поразился, насколько много людей пытаются использовать ADO в качестве сред ства синхронизации. Они выполняют запрос к одной БД, а затем перенацелива ют объект Recordset на другую БД и вызывают метод Update, надеясь, что ADO синхронизирует таблицы двух БД. В ADO такая синхронизация невозможна. Зато в ADO.NET она, вроде бы, осуществима.

У объекта есть свойство AcceptChangesDuringFill, принимающее логическое значение. Это свойство, значение которого по умолчанию — True.

управляет значением свойства RowState получаемых объектом DataAdapter.

Если значение — True, значением свойства записей, получаемых объектом будет Unchanged. При значении False свойству RowState новых объектов DataRow задается значение New.

Это означает, что, задав свойству значение False, уда ется выполнить запрос к таблице одной БД, передать итоговый объект объекту DataAdapter, сконфигурированному для взаимодействия с другой и вставить в эту БД все новые записи.

Свойство Объект DataAdapter обновляет БД на основе оптимистической модели. Когда вы выбираете содержимое записи, изменяете эту запись в объекте DataSet и затем передаете отложенные изменение в БД при помощи объекта DataAdapter, обнов ление может завершиться ошибкой, если другой пользователь успел изменить содержимое этой же записи БД. Не волнуйтесь: эта ситуация подробно обсужда ется в главах 10 и Сейчас вам нужно знать лишь, что у оптимистов не все все гда работает, как надо.

Свойство ContinueUpdateOnError DataAdapter что произой дет в случае ошибки при передаче отложенных изменений объекта Зна чение этого свойства по умолчанию — False, т. е. при ошибки DataAdapter прекращает обновление. Если необходимо, чтобы в такой ситуации DataAdapter продолжил передавать отложенные изменения других объектов Data Row, задайте свойству ContinueUpdateOnError значение True.

Когда требуется, чтобы DataAdapter прекратил передачу изменений при воз никновении ошибки? отложенные изменения в объекте DataSet пред ставляют собой заказ и клиент не хочет размещать лишь часть этого заказа. Это позиция «все или Итак, перед передачей изменений вы начинаете тран закцию, и если одна из операций обновления завершилась ошибкой, откатывае те транзакцию. В данном случае нет смысла передавать оставшиеся изменения, если обновление предыдущего ряда закончилось ошибкой.

ГЛАВА 5 Получение данных с помощью объектов DataAdapter Методы объекта DataAdapter В табл. 5-2 перечислены четыре метода, предоставляемых объектом 5-2. Методы объекта Метод Описание Fill Выполняет хранящийся в свойстве запрос и поме щает его результаты в объект DataTable Получает информацию схемы для запроса, хранящегося в свойстве SelectCommand Возвращает массив с параметрами для свойства SelectCommand Update Передает в БД изменения, хранящиеся в объекте или Метод Fill При вызове метода выполняется запрос, хранящийся в свойстве SelectCommand, и его результаты помещаются во вложенный объект DataTable объекта DataSet. Кроме того, метод Fill возвращает 32-разрядное значение типа integer, соответствующее числу записей, полученных объектом DataAdapter, Ниже как использовать метод Fill:

Visual Basic da As New strConn) Dim As New Dim As Integer = Visual C# da = new strConn);

DataSet ds = new DataSetO;

intRowsRetrieved = Объект DataAdapter просматривает содержимое своего набора и определяет, какие объекты DataTable и указанного вами объекта DataSet использовать. Если в наборе TableMappings или объекте DataSet ожидав шейся информации схемы не обнаружено, объект DataAdapter проверяет значе ния свойств и и определяет, что предпри нять дальше.

Метод Fill объекта DataAdapter перегружен. Вместо объекта DataSet можно ука зывать DataTable. Можно также указать DataSet и строку с именем объекта который требуется заполнить или создать:

Visual Basic da As New strConn) Dim ds As New DataSetO Dim As Integer intRowsRetrieved = "Customers") Часть It Подключаемся: использование поставщика данных intRowsRetrieved = = 11, 10, Visual C# DleDbDataAdapter da = new DataSet ds = new int intRowsRetrieved;

intRowsRetrieved = intRowsRetrieved = intRowsRetrieved = 11, 10, Кроме того, у объекта есть метод Fill, полезный при создании Web требующих постраничной разбивки данных. Предположим, вы хо тите предоставить пользователям каталог в страниц, содержащих по 10 наи менований товаров. Укажите номер начальной записи и количество записей, ко торое должен получить метод Fill объекта Visual Basic Dim da As New strConn) Dim ds As New Dim intStartingRow As Integer = As = Dim intRowsRetrieved As Integer intRowsRetrieved = intStartingRow, intRowsToRetrieve, Visual C# OleDbDataAdapter da = new strConn);

DataSet ds = new int intStartingRow = 10;

int intRowsToRetrieve = 10;

int intRowsRetrieved = intStartingRow, intRowsToRetrieve, Объект передаст запрос, и если вы сообщите, что выборку данных следует начать с десятой записи (как в этом примере), DataAdapter отбро сит первые записей и просто выберет указанное вами количество записей. Если запрос (игнорируя отброшенные записи) не вернул нужное вам количество за писей, объект DataAdapter выберет все оставшиеся записи, не генерируя при этом исключение.

Оптимальный ли это способ постраничного разбиения результатов Нет. Предположим, ваш запрос возвращает 100 записей и вы хотите отображать на 10 страницах по 10 записей. Выбирая вы просто выбираете первые 10 записей. Выбирая вторую, вы отбрасываете первые 10 записей и выби раете вторую группу из 10 записей. Помните: чтобы выбрать вторую страницу, БД возвращает 20 записей. При выборке десятой страницы БД вернет все ГЛАВА 5 Получение данных с помощью объектов сей, и объект DataAdapter просто отбросит первые 90. Это выглядит но, поскольку так и есть на самом деле. Так почему же DataAdapter данную возможность? Потому, что она проста в использовании.

Более сложный и более эффективный способ той же функциональ ности — сохранять значение ключа последней записи с предыдущей вы выбираете первые 10 записей посредством такого запроса:

SELECT TOP 10 Phone FROM BY Если значение поля CustomerlD десятой записи — следующий запрос получит записи — 20:

SELECT TOP 10 CustomerlD, CompanyName, Phone FROM Customers ORDER BY CustomerlD WHERE CustomerlD > Такая архитектура повышает производительность БД, поскольку вам выбирать меньше записей. Код доступа к данным станет выполняться быстрее — для получения нужных записей вам не придется отбрасывать начальный набор записей;

кроме того, повысится производительность БД.

У объекта есть два перегруженных метода позволяющих использовать имеющийся ADO-код. Содержимое объекта Recordset ADO можно поместить в объект кроме того, можно указать объекты и имя таблицы или объекта или Recordset. Вот примеры обо их синтаксисов:

Basic As New = strConn) Dim da As New Dim ds As New Dim intRowsRetrieved As Integer intRowsRetrieved = intRowsRetrieved = da. rs) Visual C# = new = strConn, (int) da = new OleDbDataAdapterO;

OataSet ds = new int intRowsRetrieved;

intRowsRetrieved = intRowsRetrieved = 166 Часть II Подключаемся: использование поставщика данных Объект DataAdapter позволяет перенести данные из объекта Recordset ADO в объект модели ADO.NET, однако обратное перемещение невозможно.

Метод Метод позволяет до выполнения запроса получить о нем информацию схемы. Как и метод Fill, метод получает имена и типы данных всех за действованных в запросе столбцов. Кроме того, метод FillSchema получает сведе ния о допустимости для столбца значений Null и соответствующим образом зада ет значение свойства создаваемых им объектов Чтобы вам решить, как обновлять данных, метод FillScbema также пытается определить на объекте первичный ключ. Логика, реа лизующая эту операцию, сложна, но я постараюсь объяснить ее вам.

При вызове метода FillSchema объект DataAdapter сначала узнает у хранилища содержит ли указанная в запросе таблица первичный ключ. Если не со держит, объект DataAdapter проверяет наличие уникального индекса.

Обнаружив таблицу с ключом (или при его отсутствии — с уни кальным индексом), объект DataAdapter просматривает результаты запроса и ищет столбцы, указанные в первичном ключе (или уникальном индексе). Если такие стол бцы найдены, объект DataAdapter создает на их основе первичный ключ объекта DataTable. В противном случае первичный ключ на объекте DataTable не создается.

Работа с методом очень проста и напоминает использование мето да Fill за одним маленьким исключением. Как и метод FillSchema принимает объект DataSet, DataSet и имя таблицы или объект DataTable. Отличие в том, что у метода FillSchema имеется дополнительный параметр. Он позволяет нуж но ли получить информацию схемы непосредственно из источника данных или следует применить к информации схемы, возвращенной объектом DataAdapter, параметры набора TableMappings.

Можно указать любое значение из перечисления пространства имен — Source или Mapped. Если задано значение Source, DataAdapter нерирует информацию схемы, используя только полученные из источника дан ных имена столбцов. При значении Mapped объект DataAdapter обратится к со держимому набора TableMappings точно так же, как сопоставляет столбцы при вызове метода Fill. Вот примеры всех трех способов вызова FillScbema:

Visual Basic Dim da As Dim ds As New DataSet и SchemaType.

DataSet, SchemaType и имя таблицы "Table") Dim As New DataTable и ГЛАВА 5 Получение данных с помощью объектов Visual da = new 01eDbDataAdapter(strSQL, DataSet ds = new DataSet и SchemaType DataSet, SchemaType и имя таблицы DataTable = new DataTable и SchemaType Метод возвращает массив с заполняемыми им объектами Вызывая метод можно сослаться на уже существующий объект Data Table. При этом DataAdapter не перезапишет имеющиеся столбцы объекта а добавит в последний отсутствующие в нем столбцы.

Метод Метод GetFillParameters — своеобразный ярлык набора Parameters свойства Select Command объекта но с одним небольшим отличием. Метод GetFill Parameters возвращает информацию о параметрах в виде массива объектов meter, а не в виде массива объектов Parameter конкретного соответствую щего поставщику данных (например, или Если вам не требуется проверять или задавать значения свойств Precision и Scale параметров, вы сможете обращаться к параметрам посредством метода GetFillPara meters:

Visual Basic Dim As String = "SELECT & Customers WHERE CustomerlD LIKE da = New strConn) _ 5) = "ALFKI" Visual C# string strSQL = "SELECT CustomerlD, CompanyName FROM + "WHERE CustomerlD LIKE OleDbDataAdapter da = new 01eDbDataAdapter(strSQL, strConn);

5);

= "ALFKI";

Подробнее об объектах Command и Parameter — главе 4.

Метод Update Метод Update позволяет передать в хранилище данных отложенные изменения, хранящиеся в объекте DataTable или DataSet, 168 Часть II Подключаемся: использование поставщика данных Как и методы Fill и метод Update принимает объект DataSet, объект DataSet и имя таблицы или объект Метод Update предоставляет еще один перегруженный метод, массив объектов Это удобно, если вам нужно передать часть рядов таблицы, основываясь на фильтре или отношении.

Метод Update значение типа integer, соответствующее числу запи сей, успешно обновленных в хранилище данных.

Подробнее о том, как метод Update передает изменения в хранилище данных — в главе 10.

Visual Basic Dim da As Dim As DataSet Dim As Integer intChangesSubmitted = = intChangesSubmitted = As intChangesSubmitted = Visual C# da;

DataSet ds;

intChangesSubmitted;

intChangesSubmitted = intChangesSubmitted = intChangesSubmitted = intChangesSubmitted = События объекта DataAdapter В табл. 5-3 перечислены три события, предоставляемых объектом DataAdapter.

Таблица 5-3. События объекта OleDbDataAdapter Наступает, если при заполнении объекта DataSet или DataTable объект DataAdapter столкнулся с какой-либо ошибкой Наступает перед передачей измененной записи БД Наступает после передачи измененной записи в БД Событие Если при заполнении объекта DataSet или DataTable объект столкнулся с ошибкой, ее можно перехватить при помощи события FillError.

ГЛАВА 5 Получение данных с помощью Visual Basic Dim As String = & "Initial strSQL = "SELECT TOP 1 OrderlD, Orders" Dim As New strConn) = Error AddressOf da_FillError Dim As Public Sub sender As Object, e As FillErrorEventArgs) = True End Sub Visual C# string strConn, strSQL;

strConn = "Initial = "SELECT TOP OrderlD, CustomerlD, FROM Orders";

da = new strConn);

= new FillErrorEventHandler(da_FillError);

DataTable tbl = new static void da_FillError(object sender, FillErrorEventArgs e) { = true;

что с помощью события FillError нельзя перехватывать ошибки, воз никающие, если полученные объектом DataAdapter данные нарушают ограниче ния объекта DataSet или DataTable.

События и Объект DataAdapter также генерирует события при передаче в БД отложенных изменений с помощью метода Если вам нужно просмотреть отложенные изменения перед тем, как передать их в БД, воспользуйтесь событи ем RowUpdating. Чтобы сразу после передачи изменений в БД выполнить код, за дайте событие Следующий фрагмент кода демонстрирует, как использовать оба этих события.

1 70 Часть II Подключаемся: использование данных Visual Basic Dint As String = & _ "Initial strSQL = "SELECT TOP 1 EmployeelD FROM Orders" Dim da As New 01eDbDataAdapter(strSQL, strConn) AddressOf AddressOf Dim As New = + Dim cb As New = - Public Sub sender As Object, e As Event: & & "OrderlD = & & "EmployeelD & & "EmployeelD to : & End Sub Public Sub sender As Object, ByVal e As Event: & e.StatementType.ToString) & "OrderlD = & If = Then & "Errors occurred") Else & End If End Sub Visual C# string strConn, strSQL;

strConn = + "Initial StrSQL = "SELECT TOP 1 OrderlD, EmployeelD Orders";

OleDbDataAdapter da = new strConn);

+= new += new DataTable tbl = new = (int) + 1;

ГЛАВА 5 Получение данных с помощью объектов DataAdapter cb = new = (int) - 1;

static sender, e) { Event: + = + + to : + static void sender, e) { Event: + = + if == г else Вопросы, которые стоит задавать почаще Вопрос. Какой способ создания объектов DataTable, по-вашему, самый • создание объектов DataTable в коде перед заполнением их при помощи объекта DataAdapter, • явное создание объектов DataTable посредством метода • создание объектов DataTable при помощи Ответ. Настоятельно рекомендую вам первый способ. Когда я работал над этой на создание объектов DataTable в коде требовалось приблизительно в 20 раз меньше времени, чем на создание их средствами метода объекта Вопрос. Как вы и рекомендовали, я создал объекты DataTable од нако теперь код, заполняющий эти объекты, выполняется гораздо В чем же дело?

Ответ. Я рад слышать этот вопрос. Производительность снижается, если на объек тах определены ограничения. Когда вы получаете данные из хранили ща и добавляете записи в объекты проверяет новую запись на соответствие имеющимся ограничениям. Кроме ограничения, например PRIMARY KEY или UNIQUE, требуют, чтобы ADO.NET дополнительно просматривала объект DataTable и что создаваемая новая запись не 172 Часть II Подключаемся: использование поставщика данных нарушает эти ограничения. Таким при добавлении дополнительных за писей в объект производительность снижается еще сильнее.

В целом, создаваемые в объектах DataTable ограничения имеются и в БД. Если предположить, что это так, то БД уже проверила данные, которые вы собираетесь вставить в объекты DataTable. Проверять их заново нет смысла. Есть ли какой-то способ, который позволяет определять ограничения на объектах DataTable и ис ключает падение производительности, связанное с проверкой данных, получае мых при помощи метода Можно создать объекты DataTable затем заполнить их при помощи метода и только после этого добавить необходимые ог раничения — это самое элегантное решение данной проблемы.

Тем не менее команда разработчиков ADO.NET предусмотрела такую ситуацию и предлагает вам не менее изящное решение. У класса DataSet есть свойство Constraints, значение по умолчанию которого — True. Это означает, что ADO.NET гарантирует соблюдение ограничений в объекте DataSet. Однако можно непо средственно перед вызовом метода Fill объектов задать этому свой ству значение False, а по завершении — исходное значение, True:

Visual Basic = False = True = false;

= Теперь метод Fill будет получать данные так же быстро, как и в случае, когда на объектах DataTable не определены какие-либо ограничения.

АВТОНОМНАЯ РАБОТА ОБЪЕКТ DATASET МОДЕЛИ Работа с объектами DataSet три главы посвящены базовой функциональности соединенных классов объектной модели формирующих поставщика данных Теперь мы обсудим половину — классы, с помощью которых предоставляет многофункциональный, реляционный, отсоединенный кэш данных. Я расскажу об основах хранения данных в классе DataSet, а также в дру гих классах, входящих в состав объекта DataSet Возможности объекта DataSet По объект DataSet — это набор данных. Обычно разработчики представля ют результаты, возвращаемые запросом, при помощи сетки, во многом напоми нающей электронную таблицу Microsoft Excel. Объект DataSet годится для ния результатов отдельного запроса, но его скорее следует сравнивать с книгой Excel, поскольку в нем можно разместить результаты нескольких запросов.

Модель ADO.NET уже включает средство просмотра результатов запроса объект Зачем же нужен еще один объект?

Как говорилось в главе 4, DataReader — быстрая и эффективная структура, по зволяющая получать результаты запроса. Основное назначение объекта DataRea der — обеспечить высокую скорость и поэтому его функциональность ог раничена. Данные в объекте DataReader доступны только для чтения, и после пе рехода к следующей записи какой-либо возможности и просмот реть предыдущие записи.

Объект DataSet предоставляет гораздо более широкую функциональность. Рас смотрим некоторые его возможности.

ГЛАВА 6 Работа с объектами DataSet Работа с отсоединенными данными Данные в объекте DataSet отсоединены от БД. После того как вы выберете резуль таты запроса в объект DataSet с помощью объекта соединение меж ду БД и объектом перестает существовать. Изменения содержимого DataSet не на содержимом БД. Если другие пользователи изменят данные БД, соответствующие содержимому вашего объекта DataSet, вы этих из менений не увидите.

Определенно, у работы с отсоединенными структурами данных преиму щества. Первое — вам не требуется живое соединение с БД. Выбрав результаты запроса в объект DataSet, можно закрыть соединение с БД и продолжить с данными в объекте.

Отсоединенные структуры данных типа DataSet также полезны при создании многоуровневых приложений. Если ваше приложение обращается к БД с помо щью бизнес-объектов, выполняющихся на промежуточном уровне, бизнес-объектам придется передавать клиентскому приложению отсоединенные структуры данных.

Объект DataSet предназначен как раз для таких ситуаций. Его содержимое можно передать от одного компонента другому. Компонент, данные, спо собен работать с ними, как с объектом DataSet (если компонент создан основе Microsoft или как с XML-документом.

Прокрутка, сортировка, поиск и фильтрация Объект позволяет в любое время просмотреть содержимое любой своей записи. Вы вправе перемещаться по результатам запроса взад и вперед столько, сколько захотите. Благодаря этому, DataSet идеально подходит для ситуаций, ког да коду требуется циклично перемещаться по данным при создании отчетов). Кроме того, удается легко создать приложение, позволяющее перемещать ся взад-вперед по результатам запроса.

Объект DataSet также позволяет сменить способ просмотра результатов запроса, Данные в объекте разрешено сортировать по отдельному полю или груп пе полей. Можно искать запись данных по простому критерию поиска, а также определить на содержимом объекта DataSet фильтр, чтобы отображались только записи, удовлетворяющие заданным критериям. Подробнее об этом — в главе 8, Работа с иерархически организованными данными Объекты предназначены для работы с иерархически данными. В главе 2 мы с помощью мастера Data Form Wizard создали простое приложение Windows, получавшее информацию из двух таблиц — Custo mers и Orders. Форма, мастером, обеспечивает перемещение по запи сям о клиентах, и когда вы переходите от одного клиента к другому, форма ото бражает список размещенных только этим клиентом заказов.

Объект DataSet позволяет определить отношения между хранящимися в нем таблицами данных. Мастер Data Form Wizard создал похожее отношение на ос нове вашего ввода и затем связал с этим отношением объект чтобы ото бражались только заказы текущего клиента (подробнее об объекте — в следующей главе).

1 76 Часть Автономная с данными: объект DataSet модели Кэширование изменений Работать с данными, доступными только для чтения, очень просто. Одна из глав нейших проблем при создании приложения для работы с БД — преобразование ввода пользователя в изменения содержимого вашей БД. Еще большая проблема — встроить подобную в многоуровневое приложение, которому требуется кэшировать изменения, и затем передавать их все сразу в БД.

DataSet позволяет кэшировать изменения записи данных и затем пе редавать эти изменения в БД при помощи объекта DataAdapter. Кроме того, мож но просматривать измененные записи объекта DataSet и определять, как именно они изменены (вставлены, отредактированы или удалены), а также сравнивать оригинальное и текущее содержимое каждой записи.

В этой главе рассказывается, как изменять содержимое объекта DataSet. Подробнее о передаче отложенных изменений в БД с помощью объекта DataAdapter — в гла вах 10 и Интеграция с Объект DataSet модели изначально рассчитан на работу с Содер жимое DataSet можно загружать и сохранять в виде XML-документов. Кроме того, DataSet позволяет выделить информацию схемы (сведения о таблицах, столбцах и ограничениях) в файл XML-схемы, В объекты DataSet и практически взаимозаменяемы.

от одной структуры данных к другой очень просто. Благодаря такой разработчики имеют возможность выбирать наиболее удобные интерфейсы. XML-программисты могут работать с объектами DataSet, как с XML документами, а программисты БД — с как с объектами DataSet.

Подробнее об XML-функциях объекта DataSet — в главе Универсальная функциональность Разработчики, имеющие опыт работы с ADO, вероятно, знают, что возможности объекта Recordset аналогичны возможностям объекта DataSet. Например, Recordset поддерживает фильтрацию, поиск, сортировку и кэширование обновлений. Тем не менее функциональность объекта Recordset во многом определяется тем, как он открыт.

Например, если не изменять параметры по умолчанию объектов Recordset и Connection модели ADO, узнать точное число записей в объекте Recordset невоз можно. У объекта Recordset есть метод который разработчики часто ис пользуют, чтобы узнать, какая же функциональность доступна. Можно ли изме нить содержимое Если обновить запись, передаст ли Recordset измене ние в БД сразу или кэширует его? Можно ли связать Recordset с сеткой? Можно ли перейти к предыдущей записи?

Причина, по которой не все объекты Recordset предоставляют функциональность, — то, что Recordset пытается быть всем для всех. Работаете ли вы в ADO с пожарным курсором, серверным курсором или отсоединенными дан ными, вы объект Recordset.

ГЛАВА 6 Работа с объектами DataSet Объект DataSet модели не требует такой интеграции, поскольку пред назначен именно для отсоединенных данных. Как следствие, чики никогда не шлют на известный адрес электронной почты сообщений типа «Почему значение для моего равно или понимать «The is not Использование объектов DataSet DataSet и его дочерние объекты в чем-то напоминают вложенных друг в друга матрешек. Объект DataSet содержит объекты DataTable и содержит объекты и Constraint.

Вместо рассказа об использовании каждого объекта по я на про стых примерах объясню базовую функциональность объекта DataSet. А попутно и обо всех вышеперечисленных объектах.

Создание объекта DataSet Создать экземпляр объекта DataSet в коде весьма просто — достаточно восполь зоваться ключевым словом New языка по вашему выбору. У объекта DataSet есть дополнительный конструктор, позволяющий задать значение свойства DataSetName этого объекта.

Basic Dim ds As New DataSetC'DataSetName") Visual C# DataSet ds = new Класс DataSet и классы, содержащиеся в объектах — Data Constraint и DataRelation — относятся к пространству имен Просмотр структуры, создаваемой при вызове метода В главе 5 как поместить результаты запроса в объект DataSet с помощью метода Fill объекта Visual Basic Dim As String = & _ "Initial strSQL = "SELECT Phone & _ Customers" da As New strConn) Dim ds As New "Customers") 1 78 Часть III Автономная работа с данными: DataSet модели Visual C# strConn, strSQL = "SELECT Phone + "FROM Customers";

da = new strConn);

DataSet ds = new Прежде чем просмотреть результаты запроса, я расскажу о создан ной объектом для этих результатов.

Объект DataTable DataAdapter помещает результаты запроса в объект DataTable. аналогичный обсуж давшемуся главе 4 объекту Просмотреть результаты запроса можно любого этих объектов. Оба они предоставляют результаты в виде набора записей и столбцов.

Вы, вероятно, помните, что на производительность. Он позволяет быстро промчаться по результатам запроса и предоставляет очень мало дополнительной Как вы знаете, изменить данные объекта DataReader или вернуться к предыдущей записи нельзя. Объект DataTable рассчитан на хранение данных длительного пользования и предоставляет больше функци ональности, чем DataReader. Он позволяет редактировать, сортировать и фильт ровать данные;

в случае с DataReader это невозможно.

работы с этими данными длительного пользования объект DataTable пре доставляет соответствующую структуру. Свойство Columns объекта DataTable воз набор объектов DataColumn, каждый из которых соответствует столбцу результатов вашего Такая структура будет знакома программистам, имеющим опыт работы с DAO и ADO, поскольку у объекта есть свойство возвращающее набор объектов Field.

Объект DataColumn Если объекты DataColumn определяют схему вашего объекта DataTable.

Когда вы с помощью метода создаете новый объект DataTable, DataAdapter также создает объекты соответствующие столбцам на бора результатов. У этих новых объектов DataColumn заданы только самые основ ные свойства — Name, Ordinal и Следующий фрагмент кода выводит базовую информацию об объектах Data Column, создаваемых при вызове метода Visual Basic Dim strConn, strSQL As String strConn = & "Initial strSQL = "SELECT & "FROM Orders" ГЛАВА 6 Работа с объектами Dim da As New Dim As New Dim As DataTable = ds.Tables(O) information for & & DataTable") Dim col As For Each col In & Next col Visual C# string strConn, strConn = + "Initial strSQL = "SELECT + Orders";

da = new strConn);

DataSet ds = new DataTable tbl = information + tbl.TableName + (DataColumn col in + + - + Об объектах DataColumn гораздо больше информации, чем имя. положение и тип данных. Но сейчас мы ненадолго отвлечемся от объекта DataColumn и посмот рим, какие же данные поместил в новый объект DataTable.

Просмотр данных, возвращаемых объектом DataAdapter Объект DataTable сильно отличается от соответствующих объектов предыдущих моделей доступа к данным. Recordset моделей ADO и DAO, объект sultset модели RDO и объект DataReader модели ADO.NET поддерживают концеп цию «текущего ряда» данных. Все эти объекты позволяют просматривать резуль таты запроса по одной записи за раз. Объекты Recordset и управлять текущей записью при помощи методов типа и В объекте DataTable ADO.NET реализован иной подход, более щий XML-документам;

он позволяет в любой момент времени обратиться к лю бому узлу дерева. При использовании объекта DataTable всегда доступны все за писи — 24 часа в сутки. 7 дней в неделю, 365 дней в году и... ну, в общем, вы поня ли идею.

180 Часть III Автономная работа с данными: объект модели Класс предоставляет свойство Rows, возвращающее набор объектов доступных в объекте DataTable. Теперь я расскажу, как объектов DataRow просматривать результаты запроса.

Объект DataRow Объект DataRow позволяет просматривать и изменять содержимое отдельной за писи в объекте DataTable. Чтобы назначить объект DataRoiv конкретной записи в объекте воспользуйтесь свойством Rows этого объекта. Это свойство возвращает объект содержащий набор объектов DataRow. Как и DataRowCollection позволяет указать порядко вый номер элемента, к которому вы хотите обратиться.

Следующий фрагмент кода с помощью метода Fill объекта рает результаты запроса в новый объект DataTable, Затем код назначает первую возвращенную запись объекту DataRoiv и выводит содержимое двух полей этой записи.

Visual Basic Dim As String & "Initial strSQL = "SELECT & _ "FROM Orders" Dim da As New strConn) Dim ds As New "Orders") Dim As DataTable = Dim row As DataRow = = & = & Visual C# string strSQL;

StrConn = + "Initial strSQL = "SELECT EmployeelD, OrderDate + Orders";

da = new strConn);

DataSet ds = DataSetO;

DataTable tbl = DataRow row = = + = " + Как видно, назначив объект DataRow определенной записи объекта вы можете работать с данными конкретного поля так же, как и с данными объек ГЛАВА 6 Работа с объектами DataSet та У объекта DataRow есть воз содержимое конкретного поля. Можно указывать имя поля, как в пре дыдущем фрагменте кода, или целое соответствующее порядковому номе ру столбца в объекте Как и в случае с объектом DataReader, при поиске по индексу данные возвращаются чем при построчном поиске. Я исполь зовал имена столбцов только для того, чтобы сделать код более понятным.

Просмотр содержимого объекта DataRow Что, если вы хотите написать универсальную процедуру для вывода содержимо го Например, процедуру, которая принимает объект DataRow и выво дит имена и значения его полей?

Если для этого использовать объект DataReader, следует проверить его значе ние свойства и определить число поля, Затем с помощью свойств Get Name и Item получить имя и содержимое каждого поля. Однако у объекта DataRow нет аналога свойства объекта DataReader.

Вместо него объект DataRow предоставляет свойство Table, возвращающее объект DataTable, который содержит объект DataRow. Это свойство позволяет вер нуться к DataTable и получить общее число и имена столбцов. Следующий фраг мент выводит содержимое и имена полей объекта DataRow при помощи Table данного объекта:

Visual Basic Private Sub row As Dim tbl As DataTable = Dim col As For Each col In & & " & Next col End Sub Visual C# static void { DataTable tbl = foreach (DataColumn col + + + } Здесь показан третий способ просмотра содержимого конкретного поля. Ме тод Item объекта DataRow принимает объект DataColumn. На момент написания этой книги выборка содержимого записи посредством передачи объекта Data Column обеспечивала чуть более высокую производительность (примерно на 6% выше), чем поиск по порядковым номерам.

Просмотр объектов DataRow в объекте Перемещаться по объектам DataRow в объекте DataTable так же просто, как пере мещаться по любому другому набору в Framework. Используйте цикл For 1 82 Часть Автономная работа с данными: объект DataSet модели For языка по вашему выбору. Следующий фрагмент кода с помощью приво дившейся ранее процедуры просматривает содержимое объекта Data созданного при метода Visual Basic Dim As = & "Initial strSQL = "SELECT CustomerlD. " & _ "FROM Orders" da As New strConn) Dim ds As New "Orders") Dim As DataTable = Dim row As Dim As Integer Each row In intCounter += of row & intCounter) Next row Visual C# strConn, strSQL;

strConn = + "Initial strSQL = "SELECT OrderlD, CustomerlD, EmployeelD, OrderDate + Orders";

da = new strConn);

DataSet ds = new da.FilKds, DataTable tbl = int intCounter;

(DataRow row in of row ft" + intCounter);

Проверка данных в объекте DataSet БД различные механизмы проверки своих данных. В БД North wind определено множество правил и ограничений. Значения поля CustomerlD табли цы не должны превышать 5 символов и должны быть уникальными в пределах таблицы. Таблица Orders генерирует для каждой записи новое значение ГЛАВА 6 Работа с объектами DataSet и чтобы значение каждой записи одной из записей таблицы Customers.

Иногда с помощью этих же правил необходимо проверить данные в прило жении перед отправкой их в БД. Например, в Интернет-магазине вы открыли стра ницу для оформления покупки положенных в корзину товаров. Большинство ма до отправки сведений о заказе в соответствующую БД убедятся, что вы заполнили все обязательные поля.

Подобная логика кажется избыточной, поскольку в БД скорее всего уже определены похожие правила проверки. Тем не менее, добавляя правила провер ки в приложение, вы повышаете его производительность. Если пользователь слу чайно или намеренно не ввел номер кредитной карты, Web-страница с легкос не обращаясь к БД, определит, что успешная отправка сведений о заказе не возможна. Еще одно преимущество такого подхода — небольшое снижение сете вого трафика и нагрузки на БД.

DataSet модели предоставляет множество механизмов про верки аналогичных механизмам БД. Эти механизмы, также называемые ограничениями (constraints), можно разделить на две категории — ограничения уровня столбца и ограничения уровня таблицы, Свойства объекта DataColumn, используемые для проверки данных Объект DataColumn предоставляет ряд свойств для проверки данных.

Свойство Readonly Простейший способ гарантировать правильность данных — запретить пользова телям изменять их. Чтобы сделать данные объекта DataColumn доступными толь ко для задайте его свойству Readonly значение True, Свойство Одни поля БД требуют обязательно указать их а друтие принимают пустые значения — NULL. Объект DataColumn предоставляет свойство AllowDBNulI, опре деляющее, принимает ли столбец объекта значения NULL.

Свойство MaxLength Многие БД длину значения поля. Так, поле CustomerlD таблицы Customers принимает строку длиной до 5 а поле — строку длиной до 40 символов. Определить такое же ограничение на объекте DataColumn позволяет MaxLength.

Свойство Unique Свойство Unique объекта DataColumn позволяет указать уникальность значений столбца. При значении True этого свойства просматривает значения соответствующих полей каждой записи объекта Если вы, добавляя или изменяя запись объекта создадите в столбце с ограничением на уни кальность идентичное значение, сгенерирует исключение Constraint Exception.

1 84 Часть III Автономная работа с данными: объект DataSet модели ADO.NET Набор Constraints объекта DataTable Для проверки данных в объекте DataSet предназначены также свойства объекта DataTable. В объектной модели ADO.NET два класса, позволяющих определять ограничения в объекте DataTable, — и ForeignKey Constraint;

они происходят от класса Constraint. Объект DataTable предоставляет свойство при помощи которого удается добавлять, изменять и просмат ривать ограничения в объекте DataTable.

Ограничение UniqueConstraint Задав свойству Unique объекта значение вы определите в те DataTable, содержащем соответствующий столбец, ограничение на уникальность.

Одновременно с этим в набор Constraints объекта DataTable добавляется ограни чение UniqueConstraint. Задать значение свойства Unique объекта проще, чем создать новый объект UniqueConstraint в наборе Constraints объекта DataTable.

Тем не менее иногда требуется создать объект UniqueConstraint явно, например, если необходимо гарантировать уникальность комбинаций значений различных полей.

Ограничение РптагуКеу Первичный ключ — особая разновидность ограничения на уникальность. У объекта ADO.NET есть метод Find, позволяющий искать запись в объекте DataTable по значениям ее полей первичного ключа (подробнее о методе — в главе 8).

= В объекте DataTable предусмотрено ограничений на уникальность, однако первичный ключ может быть только один. Задать и просмотреть первич ный ключ объекта DataTable позволяет Ограничение ForeignKeyConstraint В объект DataTable также ограничения на внешний ключ.

Пример такого ограничения я приводил буквально пару страниц назад. Значение поля каждой записи таблицы Orders БД wind должно соответ ствовать одной из записей таблицы Customers. Чтобы определить подобное огра ничение на данных объекта DataSet, создайте объект ForeignKeyConstraint и добавьте его в Constraints объекта DataTable, данные которого требуется проверять, Обычно создавать объект ForeignKeyConstraint явно не требуется. При созда нии объекта связывающего два объекта DataTable вашего объекта DataSet, автоматически создается объект ForeignKeyConstraint. В следующей главе я познакомлю вас с объектом DataRelation и его использованием для работы с реляционными данными.

Примечание ADO.NET ничего не знает о данных БД. Ограничения, определя емые вами на столбцах и таблицах объекта DataSet, действительны только в пределах этого объекта. Очень важно помнить об этом и вот почему.

Предположим, вы определили на объекте DataTable ограничение Uni queConstraint, основанное на столбце CustomerlD. Если вы добавите за ГЛАВА 6 Работа с объектами DataSet значение поля CustomerlD которой — ZZZ2Z, сгенериру ет исключение только в случае, если в объекте есть другая за пись с таким же значением этого поля, Соблюдение ограничений на внешний ключ осуществляется таким же образом. Если определить на объекте внешний основанный на столбцах CustomerlD объектов DataTable Orders и Custo mers, ADO.NET позволит вам добавлять только те заказы, значение поля CustomerlD которых будет соответствовать одной из записей объекта DataTable Customers. Если вы попытаетесь добавить заказ, значение поля CustomerlD которого есть в БД, но в Custo mers, ADO.NET сгенерирует исключение.

Получение информации схемы с помощью метода На проверку данных требуется время. Во многих случаях не станете свойства проверки данных объекта DataSet, чтобы DataAdapter, не имея на то яв ных указаний, не задавал соответствующие свойства объектов и не ограничения в набор Constraints объекта DataTable, создавая объект DataTable посредством вызова метода Есть два способа сообщить объекту DataAdapter, что при добавлении столбцов в объект DataTable следует получить о них информацию схемы (сведения об ог раничениях): задать свойству объекта DataAdapter значение или вызвать метод (подробнее об этом — в главе 5).

Пробуйте это и только Некоторые функции ADO.NET следует использовать в приложениях как можно реже. Одна из них — выборка информации схемы для объекта DataSet с помощью объекта DataAdapter.

информации схемы средствами экономит время в период разработки. Фактически Visual Studio в период разработки генерирует объекты DataSet с помощью DataAdapter (подробнее об этом далее в этой главе). Если вы небольшое приложение для подтвер ждения концепции, то согласитесь, что при для получения информации схемы требуется писать меньше кода.

Однако если ваша программа не предназначена для выполнения произ вольных запросов, вам должны быть известны возвращаемые и поэтому функции типа в готовых вам не потребуются.

Если вы укажете объекту DataAdapter выбрать дополнительную информацию схемы с помощью метода для каждого нового объекта DataColumn объект DataAdapter получит из БД гораздо больше сведений, чем просто имя и тип дан ных. Просмотрев любой из этих DataColumn, вы убедитесь, что их свой ствам Readonly, и Unique заданы правильные значения Кроме того, DataAdapter попытается сгенерировать для объекта DataTable пер вичный ключ. Именно на данном этапе при выборке информации схемы проис ходит значительное снижение производительности, и почему.

Часть III Автономная работа с данными: объект DaiaSet модели должен к БД и определить, на какую ссылает ся ваш запрос, а затем снова обратиться к БД и получить о первич ном ключе этой таблицы. Если на таблице первичный ключ не определен, Data Adapter запросит информацию об индексах таблицы. Получив эти сведения, Data Adapter просмотрит столбцы, возвращенные запросом. Таким образом гаранти руется, что, если таблица содержит ключ из двух столбцов и запрос не ссылается сразу на оба этих поля, не станет создавать первичный ключ для объекта DataTable.

Примечание Объект DataAdapter также задает свойство новых объектов Чуть позже в этой главе я вкратце расскажу о дан ном свойстве, Подробнее о его использовании — в главе Создание объектов DataTable в коде Вы уже умеете создавать объекты DataTable с помощью методов Fill и объекта DataAdapter и знаете, что необходимо создавать собственные объекты DataTable, особенно когда требуется проверять данные средствами ограничений уровня столбца или таблицы. Теперь речь пойдет о том, как создавать объекты DataTable программно.

Создание объекта Объект DataTable создается так же, как и объект DataSet. У объекта DataTable есть дополнительный конструктор, позволяющий задать свойства этого объекта:

Visual Basic Dim As New Visual C# DataTable = new Добавление объекта DataTable в набор объекта Созданный объект DataTable можно средствами метода в набор Tables имеющегося объекта DataSet:

Visual Basic Dim As New DataSet{) Dim tbl As New Visual C# DataSet ds = new DataTable tbl = new 6 Работа с объектами DataSet в общем-то немного, но вечно умные разработчики Microsoft предоста вили нам еще более простой способ добавления нового объекта в на бор Tables объекта перегрузив метод Add объекта Создать новый объект и добавить его в набор Tables объекта DataSet можно одним вызовом:

Visual Basic As New Dim As DataTable = Visual C# DataSet ds new DataSetC);

tbl = Чтобы определить, находится ли объект DataTable в объекте DataSet, достаточно проверить значение свойства DataSet объекта DataTable. Если объект DataTable находится в наборе Tables объекта DataSet, свойство DataSet вернет DataSet. В противном случае оно вернет Nothing или null, в зависимости от используемого вами языка. Свойство DataSet объекта DataTable доступно только для чтения.

Отмечу также, что объект DataTable может находиться только в одном объек те DataSet. Чтобы добавить DataTable в несколько объектов воспользуй тесь методом Сору или Метод Сору создает новый объект DataTable с такой же структурой и тем же набором записей, что и у оригинального объекта DataTable.

Метод Clone создает объект DataTable с такой же структурой, что и метод но без записей.

Добавление столбцов в объект DataTable Пора дополнить «скелет* нашего нового объекта DataTable небольшим «мяса». Для хранения результатов запроса объекту DataTable нужны столбцы. В од ном из предыдущих разделов рассказывалось, что объект способен создавать объекты Теперь пришло время создать новые объекты Добавить эти объекты в набор Columns объекта Table позволяет который идентичен коду для добавления объекта DataTable в набор Tables объекта DataSet, Visual Basic Dim ds As New Dim tbl As DataTable = col As DataColumn = Visual DataSet ds = new DataSetO;

DataTable tbl = DataColumn col = 1 88 Часть III Автономная работа с данными: объект DalaSet модели Указание типа данных объекта При создании нового объекта DataColumn следует также указать тип хранящихся в нем данных. Просмотреть или задать тип данных объекта DataColumn можно посредством DataType этого объекта. значение свойства Datatype объекта DataColumn допустимо, пока вы не добавили данные в набор Rows объекта затем это значение разрешается только просматривать.

И хотя выбираемый вами тип данных объекта DataColumn зависит от типа данных соответствующего столбца БД, между типами данных БД и объектов Data Column нет прямого сопоставления, Например, Microsoft SQL Server предоставляет ряд типов для строковых дан ных. Определяя структуру таблицы БД SQL Server, можно указать, что строковые данные будут храниться как строка фиксированной или переменной длины, а также что должны храниться в однобайтовом (ANSI) или двубайтовом (Unicode) представлении.

Однако в строка — это строка. Независимо от того, имеет ли тип данных БД переменную или фиксированную длину, использует ли он однобайто вое или двубайтовое представление, тип данных объекта DataColumn — просто string. Свойство DataType объекта DataColumn работает с типами данных a не типами данных БД.

Значение свойства DataType объекта DataColumn по умолчанию — string. У объекта есть конструктор, позволяющий указать имя и тип данных создаваемого столбца. Метод Add объекта аналогичным об разом перегружен и позволяет указать значения свойств и DataType нового объекта создаваемого в объекте DataTable:

Visual Basic Dim ds As New Dim As DataTable = Dim col As DataColumn = Visual C# ds = new DataSetO;

DataTable tbl = DataColumn col = Тип данных свойства DataType — Type. Предыдущий фрагмент кода показыва ет, как получить значение Туре, соответствующее типу данных integer. В целях обратной совместимости Basic и Visual С* генерируют типы по средством разных функций. До функция и в и в Visual Basic, однако возвращаемые ей сведения зависели от используемого языка программирования. В результате в Visual Basic добавили функцию щающую информацию о типах.

Добавление первичного ключа Ранее я уже объяснял, чем программная проверка данных в объектах DataColumn и DataTable лучше использования объекта обращающегося для про верки данных к БД. Мои пояснения оказались бы пустым звоном, если бы я не ГЛАВА 6 Работа с объектами DataSet рассказал, как задать объектов и обеспечивающие проверку данных.

Как вы помните, я начал с описания свойств Readonly, и Unique объекта DataColumn и того, как с их помощью проверять данные стол бцов. Задать значения этих свойств в коде очень просто.

Visual Basic As New Dim As DataTable col As DataColumn = = False = Visual DataSet ds new DataSet();

DataTable tbl = DataColumn col = = false;

= 5;

= Определить первичный ключ для объекта DataTable гораздо сложнее. Свойство PrimaryKey содержит массив объектов DataColumn, в связи с чем ему нельзя про сто задать имена столбцов, составляющих первичный ключ.

Первичный ключ одних объектов DataTable состоит из единственного столб ца, а других — из комбинации столбцов. В следующем фрагменте кода вам встре тятся оба этих варианта. Первичный ключ таблицы состоит из одного а первичный ключ таблицы Order Details — из столбцов OrderlD и В каждом случае нужно создать массив объектов DataColumn и задать его свойству РггтагуКеу объекта DataTable:

Visual Basic Dim ds As New объект DataTable с именем Customers With New End With объект DataTable с именем Order Details With = New DataColumnO _ End With 1 90 Часть III Автономная работа с данными: объект DataSet модели Visual C# DataSet ds = new DataTable DataTable с именем Customers tbl = = new DataTable с именем Order Details tbl = tbl.PrimaryKey = new Примечание После того как вы определите первичный ключ автоматически задаст свойству Мои объектов составляющих этот ключ, значение False, Добавление других ограничений Наиболее широко используемое ограничение — это первичный ключ, однако в объект DataTable разрешается добавлять также и уникальные и внешние ключи. У набора Constraints объекта DataTable есть перегруженный метод Add, позволяю щий определять ограничения Key, и Следующий фрагмент кода с помощью метода Add добавляет простой и составной первичные ключи, а также создает внешний ключ.

Код добавляет в объект DataTable Customers уникальный основанный на столбце а объект DataTable Order Details — уникальный ключ, осно ванный на столбцах и Кроме того, он создает в таблице Order Details внешний чтобы гарантировать, что значениям столбца OrderlD со ответствует одна из записей таблицы Orders.

Для каждого случая коде реализовано два способа создания ограничения.

Первый пример явно создает новый объект Constraint и добавляет его в набор Constraints объекта DataTable. Выглядит это так:

Метод Add объекта принимает любой объект, наследующий от объекта Constraint, и поэтому ему можно просто передать объект или Constraint.

Второй пример создает ограничение и добавляет его в набор, tbl.

Add перегружен и позволяет создавать ограничения UniqueKey и ForeignKey. Тем не менее обычно я избегаю его и предпочитаю ГЛАВА 6 Работа с объектами DataSet создавать ограничения явно, это повышает удобочитаемость кода. Ниже я привожу оба синтаксиса, так как в некоторых случаях вам потребуются пере груженные методы создающие новое ограничение и сразу добавляющие его в набор.

Visual Basic Dim ds As New новый DataTable с именем Customers With уникальный ключ, основанный на столбце False) End With новый объект DataTable с Order Details With Details") уникальный ключ, основанный на столбцах и ProductID Dim cols As New Details", cols, False) ограничение основанное на столбце OrderlD требующее наличия соответствующих значений OrderlD в таблице Orders ForeignKeyConstraint _ _ End With Visual C# DataSet ds new DataSetC);

DataTable новый объект DataTable с Customers tbl = уникальный ключ, основанный на столбце CustomerlD Часть III Автономная работа с данными: объект DataSet модели false);

новый объект DataTable с Order Details tbl = • ключ, основанный на столбцах и ProductID DataColumn[] cols = new Details", cols, ограничение основанное на столбце OrderlD наличия соответствующих значений OrderlD в таблице Orders ForeignKeyConstraint Использование столбцов с автоинкрементом ADO.NET поддерживает столбцы с автоматическим увеличением значения (авто инкрементом) при помощи трех свойств объекта — и Если необходимо, чтобы ADO.NET генерировала для новых записей значения автоинкремента, задайте свойств Autolncrement объекта DataColumn значение Visual Basic Dim ds As New DataSetC) Dim tbl As DataTable = Dim col As DataColumn = = True = - = - = True Visual C# DataSet ds = new DataTable tbl = DataColumn col = = true;

col.AutoIncrementSeed = -1;

= -1;

= true;

ГЛАВА 6 Работа с объектами DataSet Данный фрагмент кода пометил как столбец с автоинкрементом и задал AutoIncrementStep значение -1. Настоятельно реко мендую вам задать этим свойствам указанное значение, и вот почему.

Свойства и AutoIncrementStep определяют, как ADO.NET ге нерирует новые значения. Например, если вы работаете с пустой таблицей, ADO.NET задаст полю с автоинкрементом первой записи значение AutoIncrement Seed. Генерировать последующие значения автоинкремента ADO.NET будет на основе значения свойства AutoIncrementStep.

Так, если значение свойств — True, а свойств AutoIncrementSeed и AutoIncrementStep — 2, ADO.NET сгенерирует для пяти записей следую щие значения автоинкремента: 2, 4, 6, 8, 10.

Когда вы добавляете записи в объект DataTable с помощью метода данная модель поведения несколько меняется. Предположим, вы работае те с объектом структура которого соответствует таблице Orders БД и задали свойствам AutoIncrementSeed и AutoIncrementStep объекта OrderlD значение 5. Если вы добавите записи в этот объект пока он пуст, значениея поля OrderlD данных записей равны 5, 19, 15, 20 и т. д, Однако, если вы сначала добавили записи в объект DataTable, вызвав метод и затем добавляете новые записи средствами метода значение поля OrderlD новых записей будет зависеть от полученных из БД дан ных. ADO.NET сгенерирует новые значения автоинкремента, основываясь на мак симальном значении автоинкремента, имеющемся в объекте DataTable, и значе нии свойства AutoIncrementStep.

Предположим, в этом примере максимальное текущее значение поля OrderlD в объекте DataTable — 973. Если сейчас добавить новую запись, ADO.NET сложит значение свойства AutoIncrementStep (5) и максимальное текущее значение поля OrderlD и получит новое значение автоинкремента — 978.

Важно помнить, что ADO.NET знает только о данных, хранящихся в DataTable. Следующее значение автоинкремента, которое сгенерирует БД, объек тной модели ADO.NET неизвестно. Как я сказал, максимальное значение поля OrderlD в объекте DataTable, заполненном результатами нашего запроса — 973.

запрос выбрал только заказы конкретного клиента:

SELECT OrderlD, FROM Orders WHERE = В БД значение поля OrderlD может быть больше, чем в объекте DataTable.

не способна узнать об этом сгенерирует для новых запи сей объекта DataTable значения автоинкремента, уже используемые в БД.

Я упомянул об этом, чтобы помочь вам понять, как работают функции авто инкремента в ADO.NET. Зная это, вы примете грамотные решения относительно создания новых значений автоинкремента средствами ADO.NET, В период разработки ADO.NET и Framework один разработчик спросил меня, есть ли у объекта DataTable средства постраничного представления инфор мации — ему требовалось возвращать или отображать лишь часть записей DataTable.

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

1 94 Часть III Автономная работа с данными: объект DafaSet модели Рекомендации по использованию автоинкремента использовать средства автоинкремента Неправильно: передавать в БД значения автоинкремента, генерируемые Эти значения — не более, чем метки. Пусть реальные значения генерирует БД Б главе рассказывается, как генерацию значе ний базе данных и как выбирать эти значения в записи объекта DataTable.

Неправильно: выводить автоинкремента новых записей, не в БД. БД скорее всего сгенерирует значения, отличные от со зданных ADO.NET. Пользователь вашего приложения может не знать, что значение автоинкремента, генерируемое — это метка. Если ваше приложение применяется для ввода информации о заказах, нужно ли вам, чтобы клерк, принимающий заказы от клиентов, подумал, что значение Order ID, сгенерированное — точное и сообщил это значение клиенту?

свойствам и зна -1. Это гарантирует, что ADO.NET будет генерировать значения-мет ки, которых нет в БД. Даже вы выводите эти значения в приложении, у пользователя не будет шанса ошибочно предположить, что ADO.NET ге нерирует значения соответствующие значениям, генери руемым БД, Следующий фрагмент кода заполняет объект DataTable результатами просто го запроса. Перед заполнением таблицы код добавляет в нее столбец с автоинк рементом. Поскольку запрос не возвращает значений для этого столбца, ADO.NET генерирует для всех возвращенных запросом записей собственные значения дан ного столбца.

В коде используются объекты и Я подробно расскажу о них в главе однако в данном фрагменте их использование вполне наглядно.

Заполнив объект DataTable результатами запроса, я с помощью объекта DataView вывожу «одну» страницу объекта DataTable на экран.

Да, я создал структуру объекта DataTable с помощью метода но по ступил так. только чтобы сократить фрагмент кода. В реальном приложении я не стал бы использовать этот метод. Клянусь честью скаута.

Visual Basic Dim ds As New Dim As String = _ "Initial strSQL = "SELECT & _ "FROM Customers" Dim da As New strConn) "Customers") Dim As DataTable = Dim col As = ГЛАВА 6 Работа с объектами DataSet = = = "Customers") Dim vue As New Dim intPageSize As Integer = Dim intPageNum As Integer = = > & - 1) * intPageSize & AND RowID <= & intPageNum * intPageSize Dim As Dim As Integer For intCounter = 0 to - = vue(intCounter) & & & vbTab & Next intCounter Visual DataSet = new string strConn, strConn = "Initial strSQL = "SELECT CompanyName, ContactName + "FROM Customers";

da = new strConn);

DataTable = col = col.AutoIncrement = col.AutolncrementSeed = 1;

= 1;

DataView vue = new int intPageSize = int intPageNum = 3;

= "RowID > + (intPageNum - 1) * intPageSize + RowID <= " + intPageNum * intPageSize;

DataRowView (int intCounter = 0;

intCounter < { = + + + } Стоит ли применять этот код как средство постраничного вывода данных Web-приложений? нет. Он плохо Подробнее о способах постраничного данных — в главе 14. Данный фрагмент лишь как решить некоторые интересные проблемы при помощи средств автоинкремента ADO.NET.

1 Часть III Автономная работа с данными: DataSet модели Добавление столбца, основанного на выражении Обычно администраторы БД стараются не включать в БД которые мож но получить на основе другой информации БД. Например, в таблице Order БД wind есть столбцы с ценой и количеством каждого входящего в заказ товара, но нет столбца с общей стоимостью этого товара.

Если пользователь видит общую стоимость заказанного товара, ему все равно, где она хранится.

Большинство БД разрешают применять в запросах выражения, благодаря чему в результаты запроса удается включать вычисляемые столбцы. Чтобы БД сосчита ла и вернула общую стоимость отдельных заказанных товаров, воспользуйтесь следующим запросом:

SELECT Quantity, * Quantity AS [Order Заполнив объект результатами этого запроса, вы получите столбец с результатами нужного выражения. Однако, если откорректировать в объекте DataTable значение поля UnitPrice или Quantity, содержимое вычисляемого поля останется прежним. вызвано определение вычисляемого поля нахо дится непосредственно в запросе. Когда вы получите результаты запроса, содер жимое вычисляемого столбца не ADO.NET позволяет создавать объекты основанные на выражении, того чтобы включать в запрос выражение, как показано выше, задайте это выражение свойству Expression объекта DataColumn. Когда вы станете просматри вать содержимое вычисляемого поля, ADO.NET на основе выражения вернет со ответствующие значения. После этого можно изменять состав заказа, увеличив или уменьшив количество определенного товара, и эти изменения будут отражаться на значении вычислимого поля.

Следующий фрагмент кода добавляет в объект DataTable Order Detail столбец с общей стоимостью отдельных товаров из состава заказа:

Visual Basic Dim ds As New Dim As DataTable = Details") "Quantity * UnitPrice") Visual DataSet ds = new DataSetC):

DataTable tbl = "Quantity ГЛАВА 6 Работа с объектами DataSet Примечание На самом деле это не совсем правильный для БД спо соб подсчета общей стоимости отдельных товаров из состава заказа. В таблице Order Details есть поле определяющее действующую скидку на товар. Допустимые значения этого поля — от 0 до 1. Если зна чение поля Discount — 0,25, на товар действует 25 процентная скидка.

Таким образом, правильный способ подсчета общей стоимости отдель ных товаров из состава заказа:

Quantity * - (1 Я намеренно упростил предыдущий кода, поскольку хотел заострить ваше внимание на создании вычисляемых полей, не отвлекая на тонкости структуры БД Northwind.

Свойство Expression поддерживает разные функции, включая агрегатные, ссы лающиеся на данные других объектов из состава DataSet. В следующей главе, посвященной работе с реляционными данными, я покажу, как создавать основанные на выражениях использующие агрегатные функции. Под робнее о поддерживаемых Expression функциях — в Создание объектов DataTable, соответствующих таблицам Orders и Order Details Я уже показал многие возможности объектов DataTable и Теперь давайте объединим их в один объект DataSet, Следующий фрагмент кода создает объект содержащий три объекта DataTable (показанные ранее фрагменты кода демонстрировали, как создать эти объекты DataTable по отдель ности). Параллельно код задает свойства объектов DataColumn (включая и а также ограничения и Объект создаваемый этим фрагментом кода, почти аналогичен сгенерированному в главе 2 средствами мастера Data Form Этот код до бавляет в объект DataSet пару более утонченных параметров, а также задает свойства и столбца объекта DataTable Orders, чтобы управлять значениями автоинкремента, которые генерирует для новых заказов. Кроме того, код задает значение свойства столбцов со строковыми данными.

Код создает ограничение но не заполняет набор Relations объекта DataSet (подробнее об объекте — в следующей главе).

Мастер Data Form Wizard создает объект DataSet со строгим контролем типов.

Подробно такие объекты обсуждаются в главе 9;

сейчас же рассматривайте объект DataSet со строгим контролем типов как класс, обладающий всеми возможностя ми DataSet и дополнительно предоставляющий структуры типа DataTable и Data Column, а также вполне определенные свойства вместо простых наборов. Следу ющий код создает объект DataSet без контроля типов:

Visual Basic Dim As New Dim col As DataColumn 1 98 Часть III Автономная работа с данными: объект DataSet модели Dim fk As таблицу customers With col = = col col = col = = = New End With таблицу orders col = = True = - col.AutoIncrementstep = - = True col = = False = = New End With таблицу order details With Details") col.AllowDBNull = col = col.AllowDBNull = False = col = = "0" Quantity * (1 = New DataColumnO End With ограничения ForeignKeyConstraints fk = New ГЛАВА 6 Работа с объектами DataSet fk = New Visual C# DataSet ds = new DataTable tbl;

col;

fk;

tbl = col = col.MaxLength 5;

col = 40;

col = col.MaxLength 30;

col col.MaxLength = 24;

= new DataColumn[] таблицу orders tbl = col = = true;

= -1;

= -1;

= true;

col = = false;

col.MaxLength = 5;

new таблицу order details tbl = Add( typeof col = col.AllowDBNull = false;

col = col.AllowDBNull false;

= 1;

col = 0;

200 Часть III Автономная работа с данными: объект DataSet модели * Quantity * (1 tbl.PrimaryKey = new ограничения fk = new fk = new Изменение содержимого объекта DataTabie Вы уже умеете создавать объекты DataTabie и помещать ре зультаты запросов в объекты DataTabie средствами объекта а также просматривать содержимое объекта DataTabie. Теперь поговорим о том, как до бавлять, изменять и удалять объекты Добавление нового объекта DataRow Давайте заполним созданный нами объект DataSet данными. Б главе 5 рассказы валось, как с помощью объекта DataAdapter объект DataTabie данными из БД. Кроме того, можно данные из XML-файла;

подробнее об этом — в главе Сейчас же я остановлюсь на построковой загрузке данных, У объекта DataTabie есть свойство Rows, возвращающее объект DataRowCoUection, который содержит набор объектов DataRow, Как и в случае с большинством на для добавления новых элементов в объект DataRowCoUection годится ме тод Add. Тем не менее принципы создания объектов DataRow и других различны.

Допустим, вам требуется программно добавить в объект DataTabie, уже содер жащий 10 объектов еще 10 объектов DataRow. Чтобы добавить запись в таблицу, вы задаете значения каждого поля. Но DataRow узнает структуру таб лицы, т. е. какие столбцы она содержит? У объекта DataTabie есть метод который возвращает новый объект DataRow с информацией обо всех столбцах таблицы, Visual Basic Dim row As DataRow = Visual C# row = "ALFKI";

Создав новый объект DataRow, стоит воспользоваться его свойством Item и заполнить различные поля. Кроме того, свойство позволяет просмотреть содержимое поля Item — свойство объекта DataRow по умолчанию, и по ГЛАВА 6 Работа с объектами DataSet этому его не надо явно вызывать, чтобы им воспользоваться. Если нужно задать значение одного из полей объекта укажите имя (или порядковый номер или собственно объект и требуемое значение поля.

Метод создает новую однако не добавляет ее в объект Вообще говоря, не следует моментально добавлять запись в таб лицу, поскольку в данный момент запись пуста. Полям задаются их значения по умолчанию или, если таковые не определены, значения Null. Если вы создадите новый объект DataRow и не станете сразу же добавлять его в набор Rows, то смо жете предварительно задать значения полей новой записи. Столбец таблицы не принимает значений Null и не имеет значения по умолча нию. Предположим, у вас есть объект DataTable Customers с первичным ключом, основанным на столбце CustomerlD. Если вы попытаетесь добавить в таблицу новую запись Customers, не задав значение поля CustomerlD, система сгенерирует исклю чение.

Указав значения всех нужных полей записи, можно добавить ее в объект Data Table, воспользовавшись методом Add объекта и передав ему эту запись:

Visual Basic row As DataRow = = Visual C# DataRow row = = "ALFKI";

Объект DataTable предоставляет еще один способ добавить новую запись в таблицу — метод Первый параметр данного метода — это массив значений, элементы которого соответствуют столбцам таблицы. Второй позволяет управлять значением свойства нового объекта DataRow. Если передать в качестве этого параметра False (см. ниже), значением свойства RowState объекта DataRow будет Added, как и при добавлении новой за писи средствами методов DataTableNewRow и RowsAdd.

Visual Basic Dim As = "Maria Anders", False) 202 Часть III Автономная работа с данными: объект DataSet модели Visual C# aValues = "Alfreds "Maria Anders", Когда вы передаете изменения в БД с помощью метода объект значение свойства RowState всех объектов и определяет, как обновлять БД — изменять добавлять новую или удалять имеющуюся запись. Если передать в качестве второго параметра метода значение значением свойства нового объекта DataRow будет Unmodified, Это означает, что запись не содержит отложенных из менений, которые DataAdapter должен в БД. о свойстве объекта DataRow и обновлении БД — в главе Редактирование существующей записи Есть три способа программно изменить содержимое записи. Начнем с самого простого.

При работе с объектом DataRow значение поля можно задать, используя свой ство этого объекта. Ранее в этой главе я уже говорил, как дан ного свойства поля. Свойство доступно для чтения и записи, а значит, годится и для изменения значения поля. Следующий фрагмент кода с помощью метода Find набора Rows ищет запись в объекте Custo mers и затем изменяет значения полей и Подроб нее о методе Find — в главе 8. Сейчас же будем считать данный пример своеоб разным анонсом.

Visual Basic Dim rowCustomer As DataRow = If rowCustomer Is Then о клиенте не найдена!

Else = "NewCompanyName" = "NewContactName" End If Visual C# DataRow rowCustomer;

rowCustomer = if (rowCustomer == null) о клиенте не найдена!

else { = = Второй способ обновления записи аналогичен первому за исключением что добавляются вызовы методов BeginEdit и объекта DataRow.

ГЛАВА б Работа с объектами DataSet Visual Basic Dim As DataRow rowCustomer = rowCustomer Is Nothing Then о клиенте не Else = = "NewContactName" End If Visual C# DataRow rowCustomer;

rowCustomer = if (rowCustomer == null) о клиенте не найдена!

{ rowCustomer.

= "NewCompanyName";

= rowCustomer, Методы и изменения записи. При вызове EndEdit коррективы записи Если вы решите отменить их, вызовите метод и запись в состояние на момент Есть еще одно отличие между двумя этими способами запи си. Объект предоставляет события Column Changing и с помощью которых удается просматривать измене ния записи или поля. Порядок наступления этих событий зависит от как вы изменяете запись — с вызовом методом и EndEdit или без него.

В первом примере содержимое записи менялось каждый раз при изменении содержимого одного из полей. События объекта DataTable наступают всегда, ког да вы изменяете содержимое поля. Если вызван метод BeginEdit, наступление со бытий откладывается до вызова EndEdit (если вы вызовете ванные изменения отбрасываются, и поскольку запись не обновится, никакие события не наступают).

Третий способ — свойством ItemArray, Как и свойство Item, ItemArray позволяет просматривать и редактировать содержимое записи. Отличие их в том, что рассчитано на одновременную работу с одним полем, a ItemArray принимает и возвращает элементы которого соответствуют полям.

Visual Basic Dim As = "NewCompanyName", _ 204 Часть III Автономная работа с данными: объект DataSet модели Dim As DataRow rowCustomer = rowCustomer. = Visual C# aCustomer = DataRow rowCustomer;

rowCustomer = = aCustomer;

Если вы хотите с помощью свойства отредактировать содержимое лишь отдельных полей записи, воспользуйтесь ключевым словом (Visual Basic) или null (Visual Следующий фрагмент кода пропускает поле записи и изменяет содержимое второго, третьего и четвертого полей.

Visual Basic Dim aCustomer As = "NewCompanyName", _ Dim rowCustomer As DataRow = = aCustomer Visual C# object[] aCustomer "NewCompanyName", "NewContactName", rowCustomer = = aCustomer;

Примечание При изменении содержимого объекта DataRow содержимое со ответствующей записи БД не редактируется автоматически. Изменения содержимого объекта DataRow считаются их можно позже передать в БД посредством объекта Подробнее об этом — в главах 10 и Так каким же способом изменять записи объекта Я предпочитаю вызвать поскольку при этом приходится писать четко струк турированный, удобочитаемый и простой в обслуживании код. Кроме того, в случае неожиданных проблем такой подход позволяет отменить сразу группу изменений записи.

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

Работа со значениями в объекте DataRow При тестировании бета-версии у разработчиков возникало множество во просов по поводу того, как задать полю записи БД значение Null или как прове ГЛАВА 6 Работа с объектами DataSet рить наличие в БД таких значений. содержит ли поле или запись значение Null, на самом деле очень просто.

У объекта есть метод позволяющий содержит ли поле значение Null. Как и метод IsNull принимает имя поля, его порядко вый номер или объект Ниже показано, как использовать метод IsNull объекта DataRow.

Visual Basic Dim As DataRow = If Then Null") Else not Null") End If Visual C# DataRow rowCustomer;

rowCustomer = if else not Если вам нужно задать полю значение не применяйте ключевое слово Null языков программирования. В пространстве имен System Framework есть класс свойство Value которого позволяет задавать полям записей значение Visual Basic Dim rowCustomer As DataRow rowCustomer = = C# rowCustomer;

rowCustomer = = Удаление объекта Удалить запись гораздо проще, чем изменить, — достаточно вызвать метод объекта DataRow. Тем не менее удаленная запись исключается из структуры объекта DataTable. Вместо этого помечает запись, как ожидающую уда ления. Почему же ADO.NET не удаляет объект DataRow из таблицы?

Вспомните, что объекты для хранения данных в ADO.NET играют роль кэша данных, позволяющего получать данные из БД, редактировать их в автономном режиме и затем передавать в БД отложенные изменения. Вызывая 206 Часть III Автономная работа с данными: DataSel модели Delete, вы не удаляете соответствующую запись из БД. а просто помечаете запись как ожидающую удаления, чтобы позже удалось передать это отложенное изме нение в БД. Если полностью удалить объект DataRow из при передаче отложенных изменений содержимого или DataTable соответствующая запись БД не будет удалена.

Подробнее о передаче отложенных изменений в БД — главе 10.

Исключение объекта Чтобы по-настоящему удалить запись из объекта а не просто пометить ее на удаление, воспользуйтесь методом Remove или RemoveAt класса как показано ниже. Если у есть ссылка на нужный объект используйте метод Remove. Если есть порядковый номер, вызывайте RemoveAt.

Visual Basic Dim rowCustomer As DataRow = Visual C# DataRow rowCustomer = = aCustomer;

Обычно я применяю метод Remove. Для вызова метода RemoveAt ковый номер объекта DataRow, а у DataRow нет свойств, которые возвращали бы такую информацию.

Кроме того, классы DataSet и DataTable предоставляют метод позволяю щий удалить все объекты DataRoiv без изменения структуры объекта DataSet или DataTable.

Использование свойства Объекты DataSet, DataTable и работают, как автономный кэш данных. Вы можете выполнить запрос к БД и поместить его результаты в указанные объекты.

Ранее я рассказывал, как добавлять, и удалять записи. Поскольку объек ты не соединены с БД, вносимые вами изменения не отразятся на со держимом БД. Конечно, автономное редактирование данных не особенно полез но, если позже сделанные изменения не удастся передать в БД.

ADO.NET поддерживает передачу изменений в БД. Подробнее об этой функ циональности — в главе Сейчас же мы рассмотрим принципы поддержки данной функциональности DataSet. Чтобы объекта Data ГЛАВА 6 Работа с объектами DataSet для последующей передачи в БД, какое изменение вы сделали. «Зачем», — спросите вы.

Один из способов обновления данных БД — выполнять командные запросы типа:

UPDATE SET = WHERE = AND FieldToHodify = INSERT INTO MyTable Field2, VALUES Value2, ValueN) или DELETE FROM MyTable WHERE PKField = PKValue Точно так же для обновления годятся и хранимые процедуры, Смысл в том, что логика для изменения записи отличается от логики для вставки записи и логики для удаления записи. Следовательно, для успешной передачи изменений в БД должна отслеживать, какое именно изменение вы со вершили в объекте ADO.NET хранит сведения о типе изменения в свойстве объекта которое принимает значения из перечисления DataRowState (табл. 6-1).

смотрев значение данного свойства, вы сможете определить, была ли из менена, и если да, то как именно (отредактирована, вставлена или удалена), Таблица Перечисление DataRowState Константа Значение Описание Unchanged 2 Запись не содержит отложенных Detached 1 Запись не относится к объекту DataTable Added 4 Запись добавлена в объект DataTable, но в БД Modified 16 Запись содержит отложенные Deleted 8 Запись ожидает удаления Глядя на список допустимых значений, вы можете решить, что свойство способно возвращать комбинацию значений из перечисления DataRowState, од нако это не так — свойство всегда возвращает отдельное значение. В табл. 6- показано несколько случаев редактирования записи и приводятся результирую щие значения свойства RowState.

Таблтца 6-2. Примеры редактирования записи и результирующие значения RowState Пример Значение RowState Создание записи, не относящейся к объекту DataTable:

= = Добавление новой записи в объект DataTable: Added см. след. стр.

208 Часть III Автономная работа с данными: объект DataSet модели Таблтца 6-2. (продолжение) Пример Значение Получение записи:

= Редактирование записи: Modified = Удаление записи: Deleted Просмотр отложенных изменений объекта вы просмотрели содержимое объекта и с помощью свой ства RowState нашли измененную запись. Вы уже умеете просматривать содержи мое полей записи при помощи свойства объекта Кроме того, свой ство Item позволяет определить, каким было значение поля перед редактирова нием записи.

Свойство принимает второй необязательный параметр из перечисления (табл. 6-3).

Таблица 6-3. Перечисление DataRowVersion Константа Значение Описание Current 512 Текущее значение поля Original Оригинальное значение поля Proposed Предполагаемое значение поля (действительно только при редактировании записи с использованием 1536 Команда по умолчанию говоря, есть две «версии» объекта — версия, текущее содержимое записи, и версия с исходным содержимым. Обычно для по иска записи необходимы оба этих набора сведений. Обновив запись, можно про сматривать как текущее, так и оригинальное содержимое Следующий фраг мент кода изменяет содержимое поля CompanyName в объекте DataRow и затем возвращает текущее (новое) и оригинальное значения поля.

Visual Basic Dim As DataRow = = Dim As String ГЛАВА 6 Работа с объектами DataSet Visual C# DataRow = = При редактировании записи с использованием методов еще одна версия DataRow — с «предполагаемым» содержимым. После вызова все изменения в текущей версии записи. Тем не менее до этого изменения считаются отложенными, поскольку их удается отменить вызовом метода CancelEdit.

Чтобы при редактировании записи просмотреть предполагаемое значение поля, воспользуйтесь свойством Item объекта DataRow и задайте ему значение Proposed из перечисления При применении константы Current возвраща ется значение поля по состоянию на момент вызова метода (совсем не обязательно, что это значение — оригинальное).

Давайте рассмотрим различные состояния объекта DataRow и различные зна чения, возвращаемые свойством Item в зависимости от используемого значения DataRowVersion (это похоже на то, как законопроект превращается в но без плавной анимации).

Б табл. 6-4 перечислены значения, возвращаемые свойством Item в зависимо сти от указанного значения из перечисления а также от текуще го состояния записи. Пометкой отмечены случаи, когда при вызове свойства Item со значением из перечисления DataRowVersion система генерирует исключение.

Таблица 6-4. Значения различных версий поля объекта DataRow Значение Ориги- Предпо- По умол Пример Текущее нальное лагаемое чанию Только что созданная запись, [Исключение] [Исключение] не относящаяся к какому либо объекту row = Добавление новой записи [Исключение] [Исключение] в объект DataTable:

Только что полученная Retrieved- Retrieved- [Исключение] Retrieved Value Value Value запись:

= см. след, стр.

210 Часть Автономная работа с данными: объект DalaSet модели Таблица 6-4.

Значение Предпо- По умол Пример Текущее нальное лагаемое чанию При первом изменении NeivValue поля:

= первого изменения содержимого поля:

При втором изменении 1 - содержимого поля: Value = второго - [Исключение] содержимого поля: Value После отмены изменений: 2 Retrieved [Исключение] row.BeginEditO = После удаления записи: [Исключение] Примечание При успешном редактировании изменяется текущее, но не за оригинальное При вызове метода вос станавливается поля по состоянию на момент вызова метода (совсем не что это значение — оригинальное).

Если вы попытаетесь текущие значения полей удален ной система сгенерирует исключение. Тем не менее можно бодно просматривать исходное содержимое таких записей.

Мы обсудили три из четырех значений, входящих в перечисление Теперь я расскажу о значении Default Если задать его свойству Item не вернет значение поля по умолчанию. За возврат такого значения отвеча ет свойство Значение Default из перечисления — это просто значение по умолчанию параметра, принимаемого свойством Item объек та Как я уже говорил, свойство возвращает текущее значение поля Точность данного утверждения зависит от что понимать под словом ГЛАВА 6 Работа с объектами DalaSet Если вы не редактируете вызов свойства Item без необязательного па раметра равносилен тому, как если бы вы вызвали это свойство и передали в ка честве параметра Тем не менее при редактиро вании записи метод Item, вызванный без необязательного параметра, вернет «пред значение поля.

Работа с объектами DataSet в среде Visual Studio Вы уже достаточно знаете о структуре объектов DataSet и о том, как создавать та кие объекты программно. Но вот задача: при этом приходится писать много кода!

Рассмотрим некоторые возможности среды разработки Visual Studio значи тельно упрощающие создание объектов DataSet.

Генерирование объекта DataSet на основе объектов Как уже говорилось, структура объекта DataSet обычно зависит от структуры дан ных, возвращаемых объектами и средствами этих объектов можно формировать структуру объекта DataSet Visual Studio также позволяет создавать объекты DataSet на основе объектов DataAdapter.

При работе с например Windows- или Web-формой, содержа щим объекты на основе этих объектов создаются объекты Выберите в меню Data команду Generate Dataset, щелкните в окне Properties ссылку Generate Dataset или щелкните проектирования правой кнопкой и вы берите Generate Dataset (рис. 6-1). Откроется диалоговое окно Generate Dataset 6-2).

Рис. 6-1. диалогового окна Generate Dataset 212 Часть Автономная работа с данными: объект DataSet модели a that the & to add to Orders ftddlhisdataset Рис. 6-2. Диалоговое окно Generate Dacaset В этом диалоговом окне создают новый или изменяют структуру существую щего объекта DataSet. Кроме того, здесь можно указать объекты на основе которых будет создан объект DataSet. В диалоговом окне Generate Dataset (рис. 6-2) отображаются как объекта так и имя таблицы, на ко торую он ссылается. Это позволяет легко отобрать нужные объекты DataAdapter для создания объекта DataSet. Кроме того, в диалоговом окне Generate Dataset есть флажок, позволяющий нового объекта DataSet в конструктор.

Добавленный экземпляр объекта DataSet отобразится в панели компонентов области проектирования. На рис. 6-3 я создал новый объект DataSet и добавил его экземпляр в конструктор. Если выбрать этот экземпляр, в окне Properties отобра зятся его свойства.

Заметьте: в окне Solution Explorer появится новый файл с расширением Имя этого файла соответствует имени нового объекта DataSet. «Откуда он взял — вы. Visual Studio создает новый вызывает метод объектов указанных в диалоговом окне Generate Dataset, и затем вызывает метод этого объекта DataSet, чтобы сохранить его информацию схемы в файл.

Примечание Данная функция среды Visual Studio демонстрирует, насколько полезен метод типа когда его используют надле жащим образом.

Рассмотрим созданный нами при помощи диалогового окна Generate Dataset. Дважды щелкните значок файла в окне Solution Explorer — откроется кон структор XML-схем Visual Studio (рис. 6-4);

.xsd-файл содержит обычную XML схему с несколькими дополнительными, специфичными для объекта DataSet, ат рибутами. Объекты DataTable представлены в виде вложенных элементов объек ГЛАВА 6 Работа с объектами DataSet та DataSet, а объекты — в виде вложенных элементов объектов Data Table. Если в конструкторе, представляющем щелкнуть объект или в окне Properties отобразятся их свойства.

e Рис. Новый объект DataSet да-й'йнв i Рис. 6-4. Содержимое файла схемы нового объекта DataSet 214 Часть III Автономная работа с данными: обьект DataSet модели Создание нового объекта DataSet «с нуля» Что, если вам нужно создать объект по у вас нет объектов DataAdapter, чтобы определить его структуру? Воспользуйтесь диалоговым окном Add New Item (рис. 6-5) и добавьте в проект объекта DataSet.

Add New Control Data Form Wizard A XML with DataSet Name: !

Рис. Добавление нового объекта DataSet в проект Убедитесь, что в диалоговом окне вы выбрали значок DataSet, а не XML Schema, При выборе любого из значков Visual Studio добавит в проект и запустит конструктор XML-схем. Тем не менее в.xsd-файлах объектов DataSet за дан дополнительный атрибут схемы, на основе которого Visual Studio опре деляет, как обрабатывать файл — как обычную XML-схему или как объект DataSet.

Добавив в проект объект DataSet, вы увидите такой же конструктор, как при создании DataSet на основе объектов DataAdapter, за исключением того, что объект DataSet окажется пуст. Давайте добавим в этот DataSet новый объект DataTable.

Для этого щелкните конструктор правой кнопкой и выберите Element 6-6). Можно также указать одноименную команду в меню Schema.

Примечание способна сведения схемы DataSet в формате XML-схемы, так что вполне естественно будет просматривать и структуру объектов DataSet средствами конструктора XML-схем. К сожа данный способ имеет некоторые Знакомые с XML разработчики быстро поймут, что объекты входящие в состав DataSet, соответствуют файла а разработчиков, не имеющих опыта работы с этот факт может смутить. Вероятно, в будущих версиях Visual Studio конструктор объектов Data Set, предоставляющий более гибкие возможности работы с данными.

Сейчас же я вкратце расскажу, как создавать новые объекты DataSet при помощи имеющегося интерфейса.

ГЛАВА 6 Работа с объектами DataSet I ;

'A";

New New New New group New New any New Preview Рис. 6-6. нового объекта в объект DataSet В новый объект DataTable сразу следует несколько объектов В конструкторе XML-схемы щелкните левую ячейку первой записи представляющего ваш объект DataTable. Справа от ячейки должна появиться стрелка.

Если щелкнуть ее, появится список элементов, которые разрешено добавить в объект DataTable (рис. 6-7). Чтобы добавить новый объект выберите в списке пункт Element и задайте имя добавляемого объекта. Введенный вами текст будет задан свойству объекта DataColumn, Рис. 6-7. Добавление нового объекта DataColumn в объект DataTable Чтобы задать другие свойства объекта щелкните в конструкторе XML-схемы нужный столбец. На рис. 6-8 показана часть свойств, доступных в окне Properties после выбора столбца в конструкторе. Заметьте: одни свойства специ фичны для объекта а другие относятся скорее к XML-элементам.

Некоторые свойства, добавленные на последних этапах создания объектной мо дели например объекта в окне Properties недоступны.

Создав новый объект DataSet с требуемой структурой, сохраните и закройте конструктор XML-схемы. После этого в проект будет добавлен файл схемы объекта DataSet, Чтобы добавить экземпляр DataSet в область проек тирования, выберите на вкладке Data панели инструментов Visual Studio ком понент DataSet, как если бы хотели добавить в конструктор другой компонент, например кнопку. Дважды щелкните этот компонент или перетащите его в область проектирования или в ее панель компонентов. Откроется диалоговое окно Add Dataset (рис. 6-9), 216 Часть III Автономная работа с данными: объект DataSet модели | feijMi j Рис. 6-8. Задание нового объекта Choose a or to add to the designer.

Typed s a Da t an of typed already your tivs to a that a schema, See on ' Untyped an of an untyped this you want a dataset no Help Рис. 6-9. Добавление экземпляра нового объекта DataSet В нем можно выбрать любой из входящих в проект файлов схемы объектов DataSet. Просто укажите в списке нужный объект DataSet и щелкните — в кон структор будет добавлен новый экземпляр вашего объекта DataSet.

Заметьте: если нужно добавить экземпляр нового объекта DataSet программ но, DataSet доступен как определенный в проекте новый класс. На рис. в модуль кода Visual Basic добавляется экземпляр нового объекта DataSet.

ГЛАВА 6 Работа с DataSet tticEtftofl Рис. 6-10. Программное добавление нового объекта DataSet Создание объекта DataSet без контроля типов Как я уже говорил, Visual Studio создает объекты DataSet со строгим контро лем типов (подробнее об этом — в главе 9). Но что, если такие объекты вам не нужны? Или если вам необходим экземпляр простого объекта DataSet без конт роля типов и вы хотите добавить в него объекты и в пери од разработки?

В диалоговом окне Add Dataset (рис. 6-9) имеется переключатель, позволяю щий создать объект DataSet без контроля типов. Посмотрим, как этим переклю чателем воспользоваться.

Для начала воспользуйтесь компонентом DataSet с панели инструментов Visual Studio и добавьте в конструктор еще один объект DataSet. Когда откроется диалоговое окно Add Dataset, щелкните переключатель Untyped Dataset и затем — ОК. В панели компонентов конструктора появится новый объект DataSet.

Щелкните этот объект — в окне Properties отобразятся его свойства. Чтобы добавить объекты выберите свойство Tables и щелкните ную справа кнопку (...)• Запустится редактор Visual Studio Collection Editor.

используют многие компоненты из состава Visual Studio На рис. пока зано, как этот редактор выглядит при работе с объектами входящими в состав DataSet.

Редактор Collection Editor также применяется для добавления объектов Data Column в объекты DataTable. Чтобы добавить объект выберите в Collec tion Editor нужный объект DataTable. После этого щелкните в списке справа на бор Columns и затем — кнопку (...). Откроется еще один редактор Collection Editor (рис. 6-12), предназначенный для создания объектов DataColumn.

218 Часть III Автономная работа с данными: объект DataSet модели Tables Minimum i Prefix DataTable I Help Рис. 6-11. Добавление нового объекта в объект DataSet без контроля типов Column True С Caption [...

Readonly Рис. 6-12. Добавление нового объекта в объект DataTable Добавив объекты можно определить первичный ключ объекта DataTable. Выбрав Collection Editor объект списке справа вы увиди те свойство Щелкните его, а затем — стрелку справа от него.

ся список столбцов объекта DataTable (рис. Выберите объект который станет первичным ключом объекта DataTable и затем щелкните любое свободное место редактора Collection Editor.

ГЛАВА 6 Работа с объектами DataSel on) :

Namespace Add Рис. 6-13. Определение первичного ключа объекта DataTable Кроме того, можно добавлять элементы в наборы Constraints ваших объектов DataTable. Щелкните в редакторе Collection Editor свойство Constraints объекта и затем — кнопку (...) справа от него. Откроется еще один редактор Collection (рис. 6-14), позволяющий изменять содержимое набора Constraints объекта DataTable. Если первичный ключ объекта DataTable уже определен, вы увидите, что набор Constraints уже включает один элемент.

Constraint* 1 Remove Unique Help Рис. 6-14. Добавление ограничений в объект DataTable Редактор Collection Editor позволяет добавлять ограничения и Если щелкнуть кнопку Add, появится контекстное Часть III Автономная работа с данными: объект DataSet модели предлагающее выбрать нужный тип На рис. показан интерфейс для добавления ограничений Он очень прост — вам достаточно лишь выбрать объект в состав нового уникального ключа.

Кроме того, можно указать имя ключа и сообщить, должен ли он стать первич ным ключом объекта Unique tome:

fconstraint;

ft-irnarytey Help Рис. 6-15. Добавление нового ограничения UniqueConstraint в объект На рис. 6-16 показан интерфейс для добавления Он не требует дополнительных пояснений, так как практически идентичен интерфейсу, средствами которого мы в главе 2 определяли отношение между таб лицами Customers и Orders из состава DataSet, Рис. 6-16. Добавление нового ограничения в объект DataTable ГЛАВА 6 Работа с объектами Особенности объектов DataSet, и Вы уже получили представление о базовых возможностях объекта свя с ним объектов, а сейчас я детально расскажу обо всех предоставляемых этими объектами свойствах, событиях и методах.

Свойства объекта DataSet В табл. 6-5 перечислены наиболее часто используемые свойства объекта DataSet, Таблица 6-5. Свойства объекта DataSet Свойство Тип данных Описание CaseSensitive Boolean Определяет, ли регистр лов при сравнении строк String Определяет имя объекта DataSet Boolean находится ли объект DataSet в ре жиме проектирования Boolean Определяет, обеспечивает ли DataSet выпол нение определенных на нем Содержит набор динамических свойств и значений Boolean содержит ли DataSet ошибки Locale Определяет региональные параметры, ис пользуемые объектом DataSet при сравне нии строк Namespace String Содержит пространство имен, которое ADO.NET использует при записи содержимо го DataSet в XML-файл или при загрузке XML-данных в объект DataSet Prefix Siring Содержит префикс пространства имен, при меняемого ADO.NET при записи содержимо го DataSet в XML-файл или при загрузке XML-данных в объект DataSet набор вхо дящих в состав DataSet Содержит набор объектов входя щих в состав DataSet Свойство Свойство объекта определяет, различается ли регистр сим волов при сравнении строк в объекте DataSet. Значение данного свойства по умол чанию — False.

Если изменить значение свойства CaseSensitive объекта DataSet, аналогичным образом значение свойства CaseSensitive всех объектов DataTable из состава этого DataSet, для которых значение данного свойства не было задано.

Объект DataTable также предоставляет свойство 222 Часть III Автономная работа с данными: объект DataSet модели Свойство DataSetName DataSetName содержит имя объекта DataSet. Его значение можно задать в конструкторе DataSet. Если значение опущено, свойству DataSetName чески задается значение При записи содержимого DataSet XML-документ свойство DataSetName оп ределяет имя корневого элемента этого документа. Кроме данное свойство также определяет имя класса, генерируемого при создании средствами утилиты XSD.exe файла класса на основе файла XML-схемы.

Свойство Свойство DesignMode возвращает логическое значение, находится ли объект DataSet в режиме Это свойство полезно при написа нии кода в нестандартном элементе управления. Если объект DataSet использует ся в компоненте в период свойство DesignMode возвращает True. В противном случае оно возвращает False.

Объект DataTable также предоставляет свойство DesignMode. Оно доступно толь ко для чтения.

Свойство Свойство EnforceConstraints определяет, обеспечивает ли объект DataSet выполнение определенных на нем ограничений. Значение свойства данного свойства по умол чанию — True. Если нужно временно отключить задайте свойству EnforceConstraints значение False.

Если вы задали свойству EnforceConstraints значение True и текущее мое DataSet нарушает какие-либо из назначенных ограничений, ADO.NET сгене рирует исключение Свойство Свойство ExtendedProperties объекта DataSet позволяет хранить различную инфор мацию. Оно возвращает объект предназначенный для хранения разнообразных объектов. Несмотря на то. что свойство предо ставляет довольно большие рекомендую вам ограничиться хране нием простых строк.

Когда вы сохраняете содержимое схемы объекта DataSet как файл или поток, ADO.NET записывает содержимое набора ExtendedProperties в виде строк.

Объекты DataRelation и Constraint также предоставля ют свойство ExtendedProperties.

Далее как добавить в набор ExtendedProperties объекта DataSet и как обращаться к содержимому этого набора:

Visual Basic Dim ds As New свойства ГЛАВА 6 Работа с DataSet дополнительного свойства и перечисляем все расширенные свойства Dim objEnum As = Do While & = & Loop Visual "using DataSet = new DataSet();

дополнительные свойства дополнительного свойства и перечисляем все дополнительные свойства IDictionaryEnumerator objEnum = while + = + Свойство HasErrors Свойство HasErrors возвращает логическое значение, указывающее, содержат ли объекты входящие в состав DataSet, ошибки. Если вы передаете в БД пакеты изменений и задали свойству объектов значение проверяйте по завершении передачи значение свойства HasErrors объектов DataSet. Таким образом вы узнаете, все ли операции передачи изменений завер шились Объекты и также предоставляют свойство Подробнее о действиях в случае ошибок при передаче изменений в БД — в главе Свойство Locale В различных языках действуют разные правила сравнения строк. По умолчанию объект DataSet сравнивает строки, используя текущие региональные параметры системы. Изменить это поведение удается при помощи свойства Locale объекта DataSet.

Данное свойство принимает объект Culturelnfo, относящийся к пространству имен Подробнее об объекте Culturelnfo — в документации Если изменить значение свойства Locale объекта DataSet, аналогичным обра зом изменится значение свойства Locale всех объектов из состава го DataSet, для которых значение данного свойства не было задано.

224 Часть с данными: объект DataSet модели Объект также предоставляет свойство Locale.

Следующий фрагмент кода задает свойству Locale объекта DataSet значение English Visual Basic Dim As New = New Console.

Visual C# DataSet ds new = new Свойства Namespace и Prefix Свойства и задать для объекта DataSet префикс и пространство имен XML. ADO.NET использует значения этих свойств при записи содержимого DataSet в XML-файл, а также при загрузке XML-документа объект DataSet.

Объекты DataTable и DataRow также обладают свойствами Namespace и Prefix.

Подробнее о пространствах имен — в документации MSDN, Свойство Relations Свойство Relations возвращает объект содержащий входя щие в объект DataSet объекты DataRelation. Данное свойство позволяет просмат ривать, добавлять, изменять и удалять объекты DataRelation.

Свойство Tables Свойство Tables позволяет добавлять, изменять и удалять объекты DataRelation. Оно возвращает объект содержащий входящие в объект DataSet объекты DataTable.

Обращаться к объектам DataTable через свойство Tables разрешается по их имени (свойство или порядковому В последнем случае производи тельность выше.

Методы объекта DataSet В табл. 6-6 перечислены наиболее часто используемые методы объекта DataSet.

Таблица 6-6. Методы объекта DataSet Метод Описание Подтверждает все отложенные изменения в объекте Вызывается конструкторами Visual перед добавлением в объект DataSet сведений схемы Clear Удаляет из DataSet все объекты Clone Создает новый объект DataSet с идентичной схемой, но без объектов DataRow ГЛАВА 6 Работа с объектами DataSel Таблица 6-6.

Метод Описание Сору Создает новый объект с такой же схемой и объектами Вызывается конструкторами Visual Studio после в объект сведений схемы Возвращает новый объект с идентичной схемой, содержащий измененные записи оригинального объекта DataSet Возвращает содержимое объекта DataSet в виде XML-строки Возвращает схему объекта DataSet в виде XML-строки Возвращает логическое значение, указывающее, содержат ли объекты DataRow из состава DataSet отложенные изменения Загружает информацию схемы из XML-схемы и позволяет указать сок пространств элементы которых следует исключить из схемы объекта DataSet Merge Осуществляет слияние данных из другого объекта DataTable или массива объектов DataRow и данных текущего объекта DataSet Загружает XML-данные в объект DataSet из файла, объекта Stream, TextReader или XmlReader Загружает информацию XML-схемы в объект DataSet из файла, Stream, TextReader или XmlReader RejectCbanges Отменяет все отложенные изменения в объекте DataSet Reset Восстанавливает оригинальное состояние объекта DataSet, в котором он находился до инициализации Записывает содержимое объекта DataSet в XML-формате в файл, объект Stream. или XmlReader Записывает схему объекта DataSet в XML-формате в объект Stream, TextReader или XmlReader Методы и RejectChanges и RejectCbanges позволяют подтверждать и отбрасывать отложенные изменения в объекте DataSet.

Когда вы редактируете содержимое объекта ADO.NET помечает этот объект как содержащий отложенное изменение и задает его свойству RowState соответствующее значение — Added, Modified или Deleted, Кроме того, ADO.NET сохраняет оригинальное и текущее содержимое объекта DataRow.

При вызове метода объекта DataSet ADO.NET подтвердит отложенные изменения в объектах DataRow из состава вашего DataSet, Свойству RowState записей, у которых его текущее значение — Added или за дается значение Unchanged. При этом ADO.NET также сбросит «оригинальные» значения полей объектов «оригинальным» станут текущие зна чения этих полей. После вызова метода AcceptChanges из объекта DataSet удаля ются все объекты значение свойства RowState которых — Delete.

Успешно передав отложенные хранящиеся в объекте DataRow, объект DataAdapter неявно вызывает метод При вызове метода RejectChanges все отложенные изменения в объекте DataSet отбрасываются и из него удаляются все объекты DataRow, значение свойства 226 Часть III Автономная работа с данными: объект DataSet модели которых — Added. Если значение свойства объекта — Modified или восстанавливается оригинальное состояние этого объекта.

Объекты и DataRow также обладают методами и Reject Changes.

Методы Beginlnit и Методы Beginlnit и Endlnit вызываются конструкторами, и использовать их непос редственно в коде не требуется. Если в период разработки вы средствами конст рукторов Visual Studio создали объект DataSet без контроля типов, то заме тите, что конструктор сгенерировал код, использующий данные методы. Код зывает метод добавляет в объект DataSet информацию схемы и затем вызывает метод Я пытался использовать эти методы в коде, полагая, что смогу помочь вам понять, что же они делают, однако так и не обнаружил ни одного случая (например до бавление столбца, основанного на до добавления на кото рый первый столбец ссылается), который еще не был описан.

Объект DataTable также обладает методами Beginlnit и Метод Clear Метод позволяет удалить из объекта DataSet все объекты DataRou: Вызвать его быстрее, чем освободить оригинальный и создать новый DataSet с идентич ной структурой.

Объект DataTable также предоставляет метод Clear.

Методы Clone и Сору Метод Сору позволяет создать новый объект по структуре и содержимо му аналогичный оригинальному. Чтобы создать объект DataSet с идентичной струк турой, но без записей, воспользуйтесь методом Clone.

Объект DataTable также обладает методами Clone и Сору.

Метод Метод возвращает новый объект со структурой ориги нального объекта DataSet, содержащий все записи оригинального объекта DataSet с отложенными изменениями. Подробнее об этом методе — главе Объект DataTable также предоставляет метод GetChanges.

Примечание Для соответствия ограничениям ссылочной целостности, опре деленным в оригинальном объекте новый DataSet может также включать несколько неизмененных объектов DataRow. Если вы измени ли дочернюю запись, а родительскую не трогали, в новый DataSet вклю чается именно родительская запись. Если бы новый объект DataSet со держал дочернюю запись, это нарушило бы ограничение ссылочной ГЛАВА 6 Работа с объектами DataSet Методы и Метод GetXml позволяет получить содержимое объекта DataSet, в том числе ин формацию схемы, в виде строки XML-формата. Если же вам требуется только схемы, воспользуйтесь методом GetXmlSchema.

Подробнее о функциях ADO.NET для работы с XML-данными в главе 12.

Метод Метод HasChanges возвращает логическое значение, указывающее, есть ли в объекте DataSet объекты с отложенными изменениями, Рекомендую вам использовать данный метод при создании приложений, по зволяющих изменять содержимое DataSet и передающих сделанные изменения в БД при объектов Какой смысл пытаться передать отложен ные изменения из DataSet в БД, если их нет?

Метод Merge Метод Merge позволяет загрузить в имеющийся объект DataSet данные из другого объекта или массива объектов Подробнее о методе Merge — в главе 11.

Методы и Метод ReadXml позволяет загрузить в объект DataSet из объекта Stream или Для управления порядком считывания XML-дан ных применяют параметр Он принимает значения из перечисления и позволяет указать, нужно ли считывать весь XML-документ или только XML-фрагмент и требуется ли считывать XML-схему.

У объекта DataSet также есть метод позволяющий записывать его содержимое XML-формате. Данный метод предоставляет те же что и метод ReadXml о функциях ADO.NET для работы с XML-данными в главе Методы WriteXmlSchema и Методы ReadXmlSchema и WriteXmlSchema аналогичны методам ReadXml и но предназначены для работы с XML-схемами. Как и ReadXml и WriteXml, они принимают объект TextReader, XmlReader или строку с именем файла с XML данными.

Метод InferXmlSchema похож на но предоставляет расширен ные возможности управления — он позволяет указать пространства имен, элементы которых следует игнорировать. Подробнее об этом — в разделе DataSet Schema Information from XML» документации MSDN.

Подробнее о функциях ADO.NET для работы с XML-данными — в главе 12.

Метод Reset Метод Reset восстанавливает оригинальное состояние объекта DataSet, в котором он находился до инициализации. Чтобы отбросить имеющийся и начать с новым объектом используйте метод а не создавайте новый пляр DataSet, 228 Часть Автономная работа с данными: объект DataSet модели События объекта DataSet В табл. 6-7 указано наиболее часто используемое событие объекта DataSet.

Pages:     | 1 | 2 || 4 | 5 |   ...   | 8 |



© 2011 www.dissers.ru - «Бесплатная электронная библиотека»

Материалы этого сайта размещены для ознакомления, все права принадлежат их авторам.
Если Вы не согласны с тем, что Ваш материал размещён на этом сайте, пожалуйста, напишите нам, мы в течении 1-2 рабочих дней удалим его.