Тема 2. «Программирование в средах современных информационных систем»

advertisement
Тема 2. «Программирование в средах современных
информационных систем»
Цель
Рассмотреть новую стратегию доступа к данным в современных
информационных системах.
Задачи
1. Познакомиться с принципами новой стратегии доступа к
данным.
2. Изучить элементы теории модульного программирования.
3. Рассмотреть объекты доступа к данным, реализованным в
концепции ADO.NET.
Оглавление
Передача данных в современных информационных системах
Объект DataSet: свойства и методы
Объект DataTable
Объект DataRow
Объект DataColumn
Объект DataRelation
Выводы
Вопросы для самопроверки
Литература
Передача данных в современных информационных системах
Основная идея передачи данных в современных информационных
системах состоит в том, что в сегодняшнем мире, для которого
характерен
высокий
уровень
информационной
интеграции,
приложение клиента может использовать данные из множества
источников. В этой ситуации, получив требуемую информацию через
сеть за достаточно короткий промежуток времени, дальнейшую
обработку данных требуется выполнять локально, без постоянной
поддержки соединения с хранилищами данных (рис. 2.1).
Уровень пользовательского
интерфейса
XML
Промежуточный уровень
Уровень данных
DataReader
DataAdapter
Хранилище данных
Command
DataSet
Другие источники данных
Connection
Рис. 2.1. Современная технология отсоединяемого доступа к данным
Концепция ADO.NET предоставляет средства доступа к данным: через
объекты DataReader и DataSet. Объект DataReader предназначен для
последовательного считывания информации, и поэтому используется
для быстрого и эффективного доступа к потоковым данным при
непосредственном (не разрывном) соединении с источником данных.
Для реализации отсоединенного доступа к данным с последующей их
автономной обработкой в технологии ADO.NET применяется объект
DataSet. Объект DataSet можно считать главным объектом в
ADO.NET, представляющим собой копию данных, размещаемых в
оперативной памяти клиентского компьютера.
Данные в объекте DataSet могут быть организованы в реляционные
таблицы, связанные (или не связанные) между собой. По сути, объект
DataSet является временной базой данных, хранимой в оперативной
памяти, которая не связана активными подключениями с источниками
данных, из которых была извлечена информация. Чтобы разобраться,
как работает DataSet, взгляните на рис. 2.2.
DataSet
DataTable
DataColumn
DataTable
DataColumn
DataColumn
DataRow
DataColumn
DataRow
DataRelation
Рис. 2.2. Структура объекта DataSet
Из рис. 2.2 видно, что объект DataSet может включать один или
несколько объектов DataTable, в которых содержится информация,
извлеченная из хранилищ данных. Каждый объект DataTable внутри
DataSet в свою очередь включает объекты DataColumn,
определяющие столбцы, данные из которых хранятся в объекте
DataSet. Точно также внутри объекта DataSet может находиться
произвольное количество объектов DataRow, в которых размещаются
сами строки (записи) данных. Объекты DataRelation используются для
описания отношений между таблицами в DataSet.
Объект DataSet использует для передачи данных между платформами
и различными архитектурами формат XML. Формат XML позволяет
описывать иерархию данных в текстовом формате, что является
идеальным решением для коммуникации между системами путем
организации стандартного способа общения, понятного для каждой
системы. Стандарты XML разрабатываются консорциумом W3C
(независимой организацией, специально созданной для разработки и
утверждения стандартов на коммуникационные протоколы). Для того
чтобы системы могли обмениваться данными друг с другом,
информация
должна
быть
представлена
в
некотором
стандартизованном
формате
(отформатирована),
чтобы
в
дальнейшем можно было выполнить ее грамматический разбор.
Предположим, вы передаете системе фрагмент данных, который
выглядит следующим образом:
Табуреткин Василий
Вы, конечно, догадались, что речь идет об имени некоторого
человека, но с какой целью эта информация была передана? Кто этот
человек, и зачем нужна информация о нем? Рассмотрим другой
вариант представления передаваемых данных:
<Order>
<CustomerName>Табуреткин Василий</CustomerName>
</Order>
Теперь у нас появилась дополнительная смысловая информация. К
данным были добавлены теги разметки, которые говорят о том, что
некто Табуреткин Василий поместил какой-то заказ и теперь является
клиентом. Вероятно, эта и другая более детальная информация о
заказе отсылается поставщику, который должен выполнять заказ.
Подумайте о том, какие преимущества дает использование
стандартного способа разметки текстовых данных, которые могут быть
впоследствии переданы на различные платформы? В это состоит вся
сила XML.
Объект DataSet: свойства и методы
Использование объекта DataSet позволяет работать с автономными
наборами данных без активного подключения. Объект DataSet сам по
себе не представляет ничего примечательного. Фактически он
является эквивалентом базы данных на SQL Server. И точно так же,
как в обычную базу данных, в него могут быть помещены таблицы,
столбцы и строки, в нем могут создаваться отношения и ограничения.
Все перечисленные элементы формируют схему или структуру
объекта DataSet, поэтому мы по очереди рассмотрим каждый элемент.
Но перед этим разберем некоторые методы объекта DataSet более
подробно (могут быть проблемы при их вызове).
В приведенном ниже фрагменте программного кода создается новый
объект DataSet. Затем используется метод SqlDataAdapter.Fill для
помещения в пока еще пустой объект DataSet новой таблицы,
содержащей строки и столбцы, полученные в результате выполнения
запроса:
Imports System.Data.SqlClient
Dim strConnection As String="server=Persist Security Info=False;
Integrated Security=SSPI; database=HumanResources; server=abrzh"
Dim cnn As New SqlConnection(strConnection)
Dim ds As New DataSet()
Dim ad As New SqlDataAdapter(“SELECT * FROM Orders”, cnn)
da.Fill(ds)
Метод AcceptChanges фиксирует все изменения, внесенные в объект
DataSet, однако не позволяет зафиксировать их в источнике данных.
Обращаться с этим методом надо осторожнее, так как вызов этого
метода изменяет свойство RowState на Unchanged, что не позволит
внести изменения в источник данных (пропадает возможность
идентифицировать: какие данные должны быть перенесены в
источник). Если вы хотите сохранить вносимые изменения в источнике
данных, нельзя вызывать метод AcceptChanges напрямую. Лучше
воспользоваться методом Update у объекта DataAdapter, в результате
выполнения которого изменения вначале будут зафиксированы в
источнике данных, а уже потом сохранены в объекте DataSet.
Предположим, мы модифицировали данные в первой строке таблицы:
ds.Tables(0).Rows(0).Item(“Name”)=”Сидоркин”
если мы теперь вызовем метод AcceptChanges для записи изменений
в DataSet (ds.AcceptChanges), то не сможем эти изменения внести в
источник данных.
Метод GetChanges позволяет создать новый объект DataSet, в
который будут помещены строки таблиц, модифицированные с
момента предыдущего вызова метода AcceptChanges.
Dim chandesDs As DataSet=ds.GetChanges
Метод RejectChanges во многом подобен AcceptChanges в том
смысле, что выполняемые им действия не оказывают влияния на сами
источники данных. Данный метод вызывается в случае необходимости
отмены изменений, внесенных в объект DataSet. В результате его
применения все данные будут приведены в состояние, которое они
имели сразу после извлечения либо после последнего вызова метода
AcceptChanges.
Метод Reset используется для удаления всех существующих объектов
и коллекций из объекта DataSet. Это простейший способ очистки
объекта DataSet в случае, когда вы собираетесь использовать его для
выполнения новой задачи.
Объект DataTable
Фактически, объект DataTable представляет собой набор записей,
возвращаемых запросом из SqlDataAdapter. Если у вас имеется
DataTable
несколько
наборов
записей,
другими
словами вы используете более одного
запроса SELECT в свойстве SelectCommand, DataColumn DataColumn
тогда вам будет возвращена целая
DataRow
коллекция объектов DataTable.
Объект DataTable внутри объекта DataSet
может быть создан несколькими различными способами. Первый
способ подразумевает вызов метода Add свойства DataSet.Tables:
Dim ds As New DataSet()
ds.Tables.Add(“MyTable”)
Второй вариант создания: вначале описать объект DataTable, а уже
затем добавить его в объект DataSet:
Dim ds As New DataSet()
Dim tbl As New DataTable(“MyTable”)
ds.Tables.Add(tbl)
И, наконец, третий способ: создать объект DataTable при заполнении
DataSet результатами запроса к SQL Server:
Imports System.Data.SqlClient
Dim strConnection As String="server=Persist Security Info=False;
Integrated Security=SSPI; database=HumanResources; server=abrzh"
Dim cnn As New SqlConnection(strConnection)
Dim ds As New DataSet()
Dim td As DataTable
Dim ad As New SqlDataAdapter(“SELECT * FROM Orders”, cnn)
ad.TableMappings.Add(“Table”, “MyTable”)
da.Fill(ds)
td=ds.Tables(“MyTable”)
Метод TableMappings.Add объекта SqlDataAdapter позволяет
назначать имена таблицам, которые будут созданы в объекте DataSet
при его заполнении результатами выполнения команды SQL.
Для вставки строк в существующий объект DataTable имеются методы:
BeginLoadData/ EndLoadData/ LoadDataRow, NewRow/ ImportRow.
Метод BeginLoadData обеспечивает самый быстрый способ
добавления строк в таблицу. На время загрузки отключается
поддержка индексов и проверка ограничений. При вызове метода
EndLoadData выполняется перестройка индекса и активизация
ограничений. При этом все добавленные в DataTable записи
проверяются на соответствие ограничениям.
Метод LoadDataRow может использоваться для добавления
отдельных строк из любого массива данных. Выполняется проверка на
уникальность значения первичного ключа, в соответствии с проверкой
запись либо редактируется, (ключ существует), либо добавляется
вновь (ключ новый).
Dim MyValues(1) As Object
MyValues(0)=”Табуреткин”
MyValues(1)=”Василий”
ds.Tables(“MyTable”).BeginLoadData()
ds.Tables(“MyTable”).LoadDataRow(MyValues,True)
ds.Tables(“MyTable”).EndLoadData()
Методы NewRow и ImportRow выполняют создание новой строки в
существующий объект DataTable. Различия между результатами
применения методов заключаются в состоянии и значении свойств,
получаемых после добавления строки: метод NewRow выполняет
создание новой строки и устанавливает ее статус равным Added, а
при использовании метода ImportRow строка будет иметь статус
Unchanged.
Метод Select используется для возвращения массива объектов
DataRow, соответствующих определенному критерию. В качестве
такого критерия может выступать некое условие для значения столбца
либо значение статуса строки, например, Added.
В нашем примере метод Select используется для извлечения массива
объектов DataRow, для которых значение в столбце Name начинается
с буквы “Т”:
Dim drs As DataRow()
drs=ds.Tables(“Mytable”).Select(“Name like ‘Т%’”)
Объект DataRow
Данные, полученные в результате выполнения запроса, хранятся в
объекте DataRow. Поскольку связь с источником данных не
поддерживается, то для обновления информации требуется
использовать свойства и методы объекта DataRow. Рассмотрим
некоторые из них.
Свойство RowState используется при модификации данных в таблице,
будь-то удаление, изменение либо добавление строк. Каждая строка
DataRow имеет определенное значение свойства RowState, благодаря
этому значению можно определить, какие операции были
произведены над данной строкой. Начальное значение свойства
RowState для любой строки коллекции – Unchanged. После изменения
данных статус строки становится равным Modified. При удалении
строки свойство RowState получает значение Deleted.
Свойство Item позволяет извлечь данные из определенного столбца
либо поместить данные в определенный столбец. Свойство ItemArray
позволяет обрабатывать массив значений при заполнении столбцов
таблицы.
Методы BeginEdit и EndEdit используются в паре для начала и
завершения редактирования строки.
Dim rw As DataRow
rw=ds.Tables(“Mytable”).Row(0)
rw.BeginEdit(0
If rw.HasVersion(DataRowVersion.Current) Then rw.Item(“Name”)=
”Сидоркин”
rw.EndEdir(0
rw.AcceptChanges()
Объект DataColumn
Объект DataColumn используется для определения структуры объекта
DataTable. Каждый объект DataRow, добавляемый в DataTable,
должен содержать значение для всех столбцов текущей таблицы.
Важно понимать, что значения столбцов не могут быть извлечены с
помощью коллекции DataColumn объекта DataTable. Коллекция
объектов DataColumn используется исключительно для формирования
структуры, а доступ к отдельным значениям столбцов можно получить
при помощи свойства DataRow.Item. Рассмотрим наиболее
интересные свойства и методы объекта DataColumn.
Свойство AllowDBNull определяет допустимость Null-значений для
заданного столбца.
Свойство AutoIncrement говорит о том, что рассматриваемый столбец
содержит значение, автоматически генерируемое для каждой новой
строки с заданным приращением. Это свойство является
эквивалентом
столбца
Identity
в
SQL
Server.
Свойство
AutoIncrementSeed задает начальное значение для столбца так
называемых
identity
значений.
Свойство
AutoIncrementStep
определяет шаг приращения для столбца-аналога identity-значений.
Свойства ColumnName, DataType, DefaultValue задают соответственно
имя столбца, тип данных столбца, значение по умолчанию для
столбца. Свойство DataType может принимать следующие значения:
Boolean, Byte, Char, DateTime, Decimal, Double, Int16, Int32, Int64,
SByte, Single, String, TimeSpan – для оценки разности между двумя
значениями типа DateTime, UInt16, UInt32, UInt64 – для беззнаковых
целых чисел.
Dim ds As New DataSet()
Dim rw As DataRow
Dim col As DataColumn
Ds.Tables.Add(“Mytable”)
col=ds.Tables(“Mytable”).Columns.Add(“IDCol”,
Type.GetType(“System.Int32”))
col.AutoIncrement=True
col.AutoIncrementSeed=1
col.AutoIncrementStep=10
Для создания вычисляемых столбцов, либо столбцов, получаемых
путем агрегации данных, используется свойство Expression.
Рассмотрим пример, в котором для получения значения вычисляемого
столбца используются итоговые (агрегатные) функции. В следующем
программном коде определяется максимальная цена в столбце price
для таблицы Mytable, из которой затем вычитается цена в текущей
строке для подсчета разницы в столбце MaxPriceDiff:
Imports System.Data, System.Data.SqlClient
Dim strConnection As String="server=Persist Security Info=False;
Integrated Security=SSPI; database=HumanResources; server=abrzh"
Dim cnn As New SqlConnection(strConnection)
Dim ds As New DataSet()
Dim ad As New SqlDataAdapter(“SELECT * FROM Orders”, cnn)
ad.TableMappings.Add(“Table”, “MyTable”)
da.Fill(ds)
Dim col As New DataColumn()
col.DataType=Type.GetType(“System.Decimal”)
col.ColumnName=”MaxPriceDiff”
col.Expression=(“MAX(price)-price”)
ds.Tables(“Mytable”).Columns.Add(col)
Объект DataRelation
Мы уже не раз говорили, что
объект
DataSet
может
рассматриваться как некая копия
DataTable
DataTable
базы данных, размещенная в
памяти.
Однако
существует
немаловажное отличие. Тогда как
объекты
DataTable
отражают
DataRelation
структуру соответствующих таблиц
базы данных, отношения между
DataTable не могут быть получены (при заполнении DataSet с
помощью метода Fill) неявным образом на основе имеющихся
сведений об ограничениях ссылочной целостности, существующих в
базе данных. В дальнейшем вам необходимо будет воспользоваться
объектом DataRelation для создания отношений между объектами
DataTable объекта DataSet, чтобы обеспечить, таким образом, защиту
целостности данных, размещенных в DataSet, а также выполнения
обновлений в дочерних объектах DataTable.
Объект DataRelation может быть создан путем вызова метода
Relations.Add объекта DataSet. Чтобы воспользоваться этим методом,
необходимо задать имя отношения, а также указать родительские и
дочерние столбцы отношения в виде имен двух объектов DataColumn,
например:
Dim ad1 As New SqlDataAdapter(“SELECT * FROM Employees”, cnn)
ad1.TableMappings.Add(“Table”, “Employees”)
Dim ad2 As New SqlDataAdapter(“SELECT * FROM Orders”, cnn)
ad2.TableMappings.Add(“Table”, “Orders”)
Dim ds As New DataSet()
da1.Fill(ds)
da2.Fill(ds)
Dim ParentCol As DataColumn=
ds.Tables(“Employees”).Columns(“EmployeeID”)
Dim ChildCol As DataColumn=
ds.Tables(“Orders”).Columns(“EmployeeID”)
Ds.Relations.Add(“FK_Departments”, ParentCol, ChildCol)
Как видите, мы создали два новых объекта DataColumn: один для
столбца, выступающего в роли родительской части, а другой – для
столбца ключа дочерней части отношения. Если бы мы захотели
создать отношений из нескольких столбцов, нам понадобилось бы
DataSet
создать массив объектов DataColumn и перечислить их все при
создании отношения с помощью объекта DataRelation.
Чтобы заставить DataRelation поддерживать целостность данных
между объектами DataTable, необходимо создать ограничение,
обеспечивающее реализацию отношений между родительскими и
дочерними
объектами
DataColumn,
а
значение
свойства
EnforceConstraints объекта dataset установить равным True. Данное
ограничение реализуется в виде ограничения уникальности
UniqueConstraint для родительских таблиц и в качестве ограничения
внешнего ключа для дочерних таблиц. Указанные ограничения
создаются автоматически при определении отношения либо могут
быть созданы независимо от объекта DataRelation для поддержки
других (не ссылочных) ограничений целостности данных, например,
ограничений уникальности или ключей-кандидатов.
Ограничение уникальности UniqueConstraint означает, что для каждой
строки значение в данном столбце или столбцах должно являться
уникальным (неповторяющимся). Ограничение имеет набор свойств,
которые можно изменять.
Ограничение внешнего ключа ForeignKeyConstraint необходимо в
случае, если значение в данном столбце одной таблицы должно
соответствовать одному их значений столбца другой таблицы.
Реализация такого типа ограничений позволяет защитить вас от
ошибок в логике приложений, когда в одну таблицу добавляются
данные, зависимые от несуществующей строки другой таблицы.
Объект
ForeignKeyConstraint
также
имеет
набор
свойств,
предназначенных
для
изменения.
Аналогично
ограничению
уникальности, ограничения внешнего ключа могут создаваться
автоматически при определении отношения DataRelation между
объектами DataTable.
Целостность данных вполне может поддерживаться и без создания
объекта DataRelation. Но в этом случае вы не сможете осуществлять
навигацию между таблицами при помощи коллекции отношений
объекта DataSet либо свойств ChildRelations и ParentRelations
отдельных таблиц.
Выводы
На сегодняшний день актуальными являются технологии доступа к
данным, позволяющие выполнять распределенную обработку
информации в автономном (отключенном) от источника режиме.
Концепция ADO.NET предоставляет разработчику средства доступа к
данным и средства хранения данных в автономном режиме. Мы
рассмотрели функциональность модели ADO.NET в отключенном от
источника данных режиме работы. Изучили объект модели DataSet и
связанные с ним объекты DataTable, DataRow, DataColumn,
DataRelation, Constraint.
Вопросы для самопроверки
1. В чем заключается современная идея передачи данных в
распределенные приложения от удаленных источников данных?
2. Какие возможности предоставляет концепция .NET для
реализации современной идеи доступа к удаленным данным?
3. Какова структура объекта DataSet, реализующего автономное
хранение данных в технологии ADO.NET?
4. Какие преимущества дает использование стандартного способа
разметки текстовых данных, которые могут быть впоследствии
переданы на различные платформы?
5. Как поместить данные из источника в объект приложения
DataSet?
6. Какие проблемы могут возникать при использовании метода
AcceptChanges объекта DataSet?
7. Какие способы создания объектов DataTable вы можете
перечислить?
8. Каким образом можно найти нужную информацию в автономном
хранилище данных?
9. Почему свойство RowState можно считать наиболее важным для
объекта DataRow?
10.
Какова роль объекта DataColumn в структуре объекта
DataSet?
11.
Наблюдается ли полное соответствие типов данных
платформы .NET и значений свойства DataType объекта
DataColumn?
12.
Можно ли в структуру объекта DataColumn добавлять
вычисляемые столбцы? Каким образом?
13.
Для чего используется объект DataRelation? Можно ли
обойтись без него?
Литература
1. Т. Бэйн, Д. Госнелл, Дж. Уолш. Visual Basic .NET и SQL Server
2000: эффективный уровень данных. / Пер. с англ.; Под ред.
С.М. Молявко. – М.: БИНОМ. Лаборатория знаний, 2006. – 604 с.,
ил.
2. Объектно-ориентированное
программирование
в
Visual
Basic.NET. Библиотека программиста / Д. Кларк. — СПб.: Питер,
2003. — 352 с.: ил.
3. Эпплман Д. Переход на VB.NET: стратегии, концепции, код. —
СПб.: Питер, 2002. — 464 с.: ил.
4. Троелсен Э. C# и платформа .NET. Библиотека программиста —
СПб.: Питер, 2006 — 796 с.: ил.
Download