Dataadapter c что это
Перейти к содержимому

Dataadapter c что это

  • автор:

Использование DataAdapter для работы c DataSet

Адаптеры данных предлагают простой и гибкий механизм заполнения объектов типа DataSet данными. Для того чтобы этот механизм начал работать, достаточно у существующего объекта типа DataAdapter вызвать метод Fill. Он использует командный объект, на который ссылается свойство SelectCommand. Этот метод представлен в нескольких модификациях, доступных для программиста. Вот прототипы некоторых из них:

public int Fill(DataSet)

public int Fill(DataTable)

public int Fill(DataSet,string)

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

Рассмотрим простой пример:

public class TestFillMethod : Form private DataGrid dataGrid;

private SqlDataAdapter adapt;

private DataSet dataSet;

SqlDataAdapter adapt = new SqlDataAdapter(

«SELECT CustomerlD, AccountNumber FROM

dataSet = new DataSet ();

Clientsize = new System.Drawing.Size(292, 273);

dataGrid = new DataGrid();

Text = «Test Fill Method»;

static void Main()

В результате работы этой программы на экране отобразится следующее окно:

Этот пример наглядно показывает то, как можно всего за несколько минут создать приложение, на которое ушло бы в несколько раз больше времени при программировании с использованием MFC или Java.

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

  • • установить свойство EnforceConstraints объекта типа DataSet в false;
  • • использовать методы DataTable — BeginLoadData и EndLoadData, которые отключают события и исключения, связанные с проверкой данных на время загрузки.

Так, в предыдущем примере можно было использовать следующие строки:

Этот код полностью аналогичен следующему:

Обновление источников данных с объектами DataAdapter

Метод Update объекта DataAdapter вызывается для решения задачи по передаче изменений из DataSet обратно в источник данных. Метод Update , как и метод Fill , принимает в качестве аргументов экземпляр DataSet , а также (необязательно) объект DataTable или имя DataTable . Экземпляр DataSet представляет собой объект DataSet , который содержит выполненные изменения, а DataTable указывает на таблицу, из которой должны быть получены эти изменения. Если ни один объект DataTable не задан, используется первый объект DataTable в DataSet .

При вызове метода Update в DataAdapter анализируются внесенные изменения и выполняется соответствующая команда (INSERT, UPDATE или DELETE). Если в DataAdapter обнаруживается изменение в DataRow, то в этом объекте используется команда InsertCommand, UpdateCommand или DeleteCommand для обработки этого изменения. Это позволяет максимально повысить производительность приложения ADO.NET путем задания синтаксиса команды во время разработки, а также, по возможности, за счет применения хранимых процедур. Необходимо явно задавать команды перед вызовом Update . Если вызывается Update , и не существует подходящая команда для конкретного обновления (например, отсутствует DeleteCommand для удаленных строк), то активизируется исключение.

При использовании хранимых процедур SQL Server для изменения или удаления данных с помощью DataAdapter убедитесь, что в определении хранимой процедуры не указана инструкция SET NOCOUNT ON. В таком случае возвращается число затронутых строк, равное нулю, что DataAdapter интерпретирует как конфликт параллелизма. Это событие вызовет исключение DBConcurrencyException.

Параметры команды могут использоваться в целях указания входных и выходных значений для инструкции SQL или хранимой процедуры применительно к каждой модифицированной строке в DataSet . Дополнительные сведения см. в разделе Параметры DataAdapter.

Важно учитывать различие между обозначением строки как удаленной в DataTable и удалением этой строки. Если вызывается метод Remove или RemoveAt , строка немедленно удаляется. Любые соответствующие строки в серверном источнике данных остаются не затронутыми, если после этого будет передано значение DataTable или DataSet в DataAdapter и вызван метод Update . Если же используется метод Delete , то строка остается в DataTable и отмечается как предназначенная для удаления. Если после этого будет передано значение DataTable или DataSet в DataAdapter и вызван метод Update , то соответствующая строка в серверном источнике данных становится удаленной.

Если значение DataTable сопоставляется или создается на основе одной таблицы базы данных, то можно воспользоваться тем, что объект DbCommandBuilder автоматически создает объекты DeleteCommand , InsertCommand и UpdateCommand для DataAdapter . Дополнительные сведения см. в статье Создание команд с помощью классов CommandBuilder.

Использование объекта UpdatedRowSource для сопоставления значений с набором данных

Можно управлять тем, как значения, возвращенные из источника данных, сопоставляются в обратном направлении с DataTable вслед за вызовом метода Update объекта DataAdapter с использованием свойства UpdatedRowSource объекта DbCommand. Задавая значение свойства UpdatedRowSource равным одному из значений перечисления UpdateRowSource, можно управлять тем, должны ли пропускаться выходные параметры, возвращаемые командами DataAdapter , или применяться к изменившейся строке в DataSet . Можно также указать, применяется ли первая возвращенная строка (если она существует) к изменившейся строке в DataTable .

В следующей таблице приведено описание различных значений перечисления UpdateRowSource и показано, как они влияют на поведение команды, используемой в сочетании с DataAdapter .

Перечисление UpdatedRowSource Описание
Both И выходные параметры, и первая строка возвращенного результирующего набора могут быть сопоставлены с модифицированной строкой в DataSet .
FirstReturnedRecord Только данные из первой строки возвращенного результирующего набора могут быть сопоставлены с модифицированной строкой в DataSet .
None Любые выходные параметры или строки возвращенного результирующего набора пропускаются.
OutputParameters Только выходные параметры могут быть сопоставлены с модифицированной строкой в DataSet .

Метод Update позволяет решить задачу по передаче внесенных изменений обратно в источник данных; но может оказаться так, что другие клиенты уже внесли изменения в данные источника данных с того момента, как последний раз было осуществлено заполнение DataSet . Чтобы обновить применяемый объект DataSet с использованием текущих данных, воспользуйтесь DataAdapter и методом Fill . Произойдет добавление новых строк к таблице, а обновленная информация будет включена в существующие строки. Метод Fill определяет, должна ли быть добавлена новая строка или обновлена существующая строка, путем проверки значений первичного ключа в строках объекта DataSet и в строках, возвращенных SelectCommand . Если в методе Fill обнаруживается значение первичного ключа какой-то строки в DataSet , которое совпадает со значением первичного ключа строки в результатах, возвращенных SelectCommand , то метод обновляет существующую строку на основании данных из строки, возвращенной SelectCommand , и задает значение RowState существующей строки, равное Unchanged . Если строка, возвращенная SelectCommand , имеет значение первичного ключа, не совпадающее ни с одним из значений первичного ключа в строках в DataSet , то метод Fill добавляет новую строку со значением RowState , равным Unchanged .

Если метод SelectCommand возвращает результаты инструкции OUTER JOIN, то DataAdapter не задает значение PrimaryKey для результирующего набора DataTable . Необходимо непосредственно определить значение PrimaryKey для обеспечения того, чтобы решение по обработке повторяющихся строк было принято правильно. Дополнительные сведения см. в разделе Определение первичных ключей.

Для обработки исключений, которые могут возникнуть при вызове Update метода, можно использовать RowUpdated событие для реагирования на ошибки обновления строк по мере их возникновения (см. раздел Обработка событий DataAdapter) или задать для параметра DataAdapter.ContinueUpdateOnError значение true перед вызовом Update и реагировать на сведения об ошибке, хранящиеся в RowError свойстве конкретной строки по завершении обновления (см. раздел Сведения об ошибке строки).

Вызов AcceptChanges применительно к DataSet , DataTable или DataRow приводит к тому, что все значения Original , относящиеся к DataRow , перезаписываются значениями Current , относящимися к DataRow . Если были изменены значения полей, уникальным образом идентифицирующих строку, то после вызова метода AcceptChanges значения Original больше не будут соответствовать этим значениям в источнике данных. Метод AcceptChanges вызывается автоматически для каждой строки во время вызова метода Update объекта DataAdapter . Можно сохранить первоначальные значения во время вызова метода Update, для чего вначале следует задать значение свойства AcceptChangesDuringUpdate объекта DataAdapter равным false, или создать обработчик событий для события RowUpdated и задать значение Status, равное SkipCurrentRow. Дополнительные сведения см. в разделах Слияние содержимого набора данных и Обработка событий DataAdapter.

Пример

В следующих примерах показано, как выполнить обновления применительно к модифицированным строкам путем явного задания значения UpdateCommand объекта DataAdapter и вызова его метода Update . Обратите внимание на то, что задан параметр, указанный в предложении WHERE инструкции UPDATE, чтобы использовалось значение Original объекта SourceColumn . Это важно, поскольку значение Current могло быть изменено, поэтому может не соответствовать этому значению в источнике данных. Значение Original представляет собой значение, которое использовалось для заполнения DataTable из источника данных.

static void AdapterUpdate(string connectionString) < using (SqlConnection connection = new(connectionString)) < SqlDataAdapter dataAdapter = new( "SELECT CategoryID, CategoryName FROM Categories", connection) < UpdateCommand = new SqlCommand( "UPDATE Categories SET CategoryName = @CategoryName " + "WHERE CategoryID = @CategoryID", connection) >; dataAdapter.UpdateCommand.Parameters.Add( "@CategoryName", SqlDbType.NVarChar, 15, "CategoryName"); SqlParameter parameter = dataAdapter.UpdateCommand.Parameters.Add( "@CategoryID", SqlDbType.Int); parameter.SourceColumn = "CategoryID"; parameter.SourceVersion = DataRowVersion.Original; DataTable categoryTable = new(); dataAdapter.Fill(categoryTable); DataRow categoryRow = categoryTable.Rows[0]; categoryRow["CategoryName"] = "New Beverages"; dataAdapter.Update(categoryTable); Console.WriteLine("Rows after update."); foreach (DataRow row in categoryTable.Rows) < < Console.WriteLine(": ", row[0], row[1]); > > > > 
Private Sub AdapterUpdate(ByVal connectionString As String) Using connection As SqlConnection = New SqlConnection( _ connectionString) Dim adapter As SqlDataAdapter = New SqlDataAdapter( _ "SELECT CategoryID, CategoryName FROM dbo.Categories", _ connection) adapter.UpdateCommand = New SqlCommand( _ "UPDATE Categories SET CategoryName = @CategoryName " & _ "WHERE CategoryID = @CategoryID", connection) adapter.UpdateCommand.Parameters.Add( _ "@CategoryName", SqlDbType.NVarChar, 15, "CategoryName") Dim parameter As SqlParameter = _ adapter.UpdateCommand.Parameters.Add( _ "@CategoryID", SqlDbType.Int) parameter.SourceColumn = "CategoryID" parameter.SourceVersion = DataRowVersion.Original Dim categoryTable As New DataTable adapter.Fill(categoryTable) Dim categoryRow As DataRow = categoryTable.Rows(0) categoryRow("CategoryName") = "New Beverages" adapter.Update(categoryTable) Console.WriteLine("Rows after update.") Dim row As DataRow For Each row In categoryTable.Rows Console.WriteLine(": ", row(0), row(1)) Next End Using End Sub 

Столбцы AutoIncrement

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

Упорядочение вставок, обновлений и удалений

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

Можно использовать метод Select объекта DataTable для возврата массива DataRow , который ссылается только на строки с конкретным значением RowState . После этого можно передать возвращенный массив DataRow в метод Update объекта DataAdapter для обработки измененных строк. Задавая подмножество строк, подлежащих обновлению, можно управлять тем, в какой последовательности обрабатываются вставки, обновления и удаления.

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

Dim table As DataTable = dataSet.Tables("Customers") ' First process deletes. dataSet.Update(table.Select(Nothing, Nothing, _ DataViewRowState.Deleted)) ' Next process updates. adapter.Update(table.Select(Nothing, Nothing, _ DataViewRowState.ModifiedCurrent)) ' Finally, process inserts. adapter.Update(table.Select(Nothing, Nothing, _ DataViewRowState.Added)) 
DataTable table = dataSet.Tables["Customers"]; // First process deletes. adapter.Update(table.Select(null, null, DataViewRowState.Deleted)); // Next process updates. adapter.Update(table.Select(null, null, DataViewRowState.ModifiedCurrent)); // Finally, process inserts. adapter.Update(table.Select(null, null, DataViewRowState.Added)); 

Используйте DataAdapter для извлечения и обновления данных

DataAdapter можно использовать для извлечения и обновления данных.

  • В этом примере DataAdapter.AcceptChangesDuringFill используется для клонирования данных в базе данных. Если свойство имеет значение false, AcceptChanges при заполнении таблицы не вызывается и позднее добавленные строки рассматриваются как вставленные строки. Таким образом, в примере эти строки используются для вставки новых строк в базу данных.
  • В этом примере DataAdapter.TableMappings используется для определения сопоставления между исходной таблицей и DataTable.
  • В этом примере DataAdapter.FillLoadOption используется для определения того, как адаптер заполняет DataTable из DbDataReader. При создании объекта DataTable можно выполнять запись данных из базы данных только в текущую или исходную версию путем установки свойства в LoadOption.Upsert или LoadOption.PreserveChanges.
  • В примере также обновляется таблица путем использования DbDataAdapter.UpdateBatchSize для выполнения пакетных операций.

Перед компиляцией и выполнением примера необходимо создать образец базы данных:

USE [master] GO CREATE DATABASE [MySchool] GO USE [MySchool] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[Course]([CourseID] [nvarchar](10) NOT NULL, [Year] [smallint] NOT NULL, [Title] [nvarchar](100) NOT NULL, [Credits] [int] NOT NULL, [DepartmentID] [int] NOT NULL, CONSTRAINT [PK_Course] PRIMARY KEY CLUSTERED ( [CourseID] ASC, [Year] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[Department]([DepartmentID] [int] IDENTITY(1,1) NOT NULL, [Name] [nvarchar](50) NOT NULL, [Budget] [money] NOT NULL, [StartDate] [datetime] NOT NULL, [Administrator] [int] NULL, CONSTRAINT [PK_Department] PRIMARY KEY CLUSTERED ( [DepartmentID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY] GO INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C1045', 2012, N'Calculus', 4, 7) INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C1061', 2012, N'Physics', 4, 1) INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C2021', 2012, N'Composition', 3, 2) INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C2042', 2012, N'Literature', 4, 2) SET IDENTITY_INSERT [dbo].[Department] ON INSERT [dbo].[Department] ([DepartmentID], [Name], [Budget], [StartDate], [Administrator]) VALUES (1, N'Engineering', 350000.0000, CAST(0x0000999C00000000 AS DateTime), 2) INSERT [dbo].[Department] ([DepartmentID], [Name], [Budget], [StartDate], [Administrator]) VALUES (2, N'English', 120000.0000, CAST(0x0000999C00000000 AS DateTime), 6) INSERT [dbo].[Department] ([DepartmentID], [Name], [Budget], [StartDate], [Administrator]) VALUES (4, N'Economics', 200000.0000, CAST(0x0000999C00000000 AS DateTime), 4) INSERT [dbo].[Department] ([DepartmentID], [Name], [Budget], [StartDate], [Administrator]) VALUES (7, N'Mathematics', 250024.0000, CAST(0x0000999C00000000 AS DateTime), 3) SET IDENTITY_INSERT [dbo].[Department] OFF ALTER TABLE [dbo].[Course] WITH CHECK ADD CONSTRAINT [FK_Course_Department] FOREIGN KEY([DepartmentID]) REFERENCES [dbo].[Department] ([DepartmentID]) GO ALTER TABLE [dbo].[Course] CHECK CONSTRAINT [FK_Course_Department] GO 
using System; using System.Data; using System.Data.Common; using System.Data.SqlClient; using System.Linq; using CSDataAdapterOperations.Properties; namespace CSDataAdapterOperations.Properties < internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase < private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); public static Settings Default < get < return defaultInstance; >> [global::System.Configuration.ApplicationScopedSettingAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("Data Source=(local);Initial Catalog=MySchool;Integrated Security=True")] public string MySchoolConnectionString < get < return ((string)(this["MySchoolConnectionString"])); >> > > class Program < static void Main(string[] args) < Settings settings = new Settings(); // Copy the data from the database. Get the table Department and Course from the database. String selectString = @"SELECT [DepartmentID],[Name],[Budget],[StartDate],[Administrator] FROM [MySchool].[dbo].[Department]; SELECT [CourseID],@Year as [Year],Max([Title]) as [Title], Max([Credits]) as [Credits],Max([DepartmentID]) as [DepartmentID] FROM [MySchool].[dbo].[Course] Group by [CourseID]"; DataSet mySchool = new DataSet(); SqlCommand selectCommand = new SqlCommand(selectString); SqlParameter parameter = selectCommand.Parameters.Add("@Year", SqlDbType.SmallInt, 2); parameter.Value = new Random(DateTime.Now.Millisecond).Next(9999); // Use DataTableMapping to map the source tables and the destination tables. DataTableMapping[] tableMappings = ; CopyData(mySchool, settings.MySchoolConnectionString, selectCommand, tableMappings); Console.WriteLine("The following tables are from the database."); foreach (DataTable table in mySchool.Tables) < Console.WriteLine(table.TableName); ShowDataTable(table); >// Roll back the changes DataTable department = mySchool.Tables["Department"]; DataTable course = mySchool.Tables["Course"]; department.Rows[0]["Name"] = "New" + department.Rows[0][1]; course.Rows[0]["Title"] = "New" + course.Rows[0]["Title"]; course.Rows[0]["Credits"] = 10; Console.WriteLine("After we changed the tables:"); foreach (DataTable table in mySchool.Tables) < Console.WriteLine(table.TableName); ShowDataTable(table); >department.RejectChanges(); Console.WriteLine("After use the RejectChanges method in Department table to roll back the changes:"); ShowDataTable(department); DataColumn[] primaryColumns = < course.Columns["CourseID"] >; DataColumn[] resetColumns = < course.Columns["Title"] >; ResetCourse(course, settings.MySchoolConnectionString, primaryColumns, resetColumns); Console.WriteLine("After use the ResetCourse method in Course table to roll back the changes:"); ShowDataTable(course); // Batch update the table. String insertString = @"Insert into [MySchool].[dbo].[Course]([CourseID],[Year],[Title], [Credits],[DepartmentID]) values (@CourseID,@Year,@Title,@Credits,@DepartmentID)"; SqlCommand insertCommand = new SqlCommand(insertString); insertCommand.Parameters.Add("@CourseID", SqlDbType.NVarChar, 10, "CourseID"); insertCommand.Parameters.Add("@Year", SqlDbType.SmallInt, 2, "Year"); insertCommand.Parameters.Add("@Title", SqlDbType.NVarChar, 100, "Title"); insertCommand.Parameters.Add("@Credits", SqlDbType.Int, 4, "Credits"); insertCommand.Parameters.Add("@DepartmentID", SqlDbType.Int, 4, "DepartmentID"); const Int32 batchSize = 10; BatchInsertUpdate(course, settings.MySchoolConnectionString, insertCommand, batchSize); > private static void CopyData(DataSet dataSet, String connectionString, SqlCommand selectCommand, DataTableMapping[] tableMappings) < using (SqlConnection connection = new SqlConnection(connectionString)) < selectCommand.Connection = connection; connection.Open(); using (SqlDataAdapter adapter = new SqlDataAdapter(selectCommand)) > > // Roll back only one column or several columns data of the Course table by call ResetDataTable method. private static void ResetCourse(DataTable table, String connectionString, DataColumn[] primaryColumns, DataColumn[] resetColumns) < table.PrimaryKey = primaryColumns; // Build the query string String primaryCols = String.Join(",", primaryColumns.Select(col =>col.ColumnName)); String resetCols = String.Join(",", resetColumns.Select(col => $"Max() as ")); String selectString = $"Select , from Course Group by "); SqlCommand selectCommand = new SqlCommand(selectString); ResetDataTable(table, connectionString, selectCommand); > // RejectChanges will roll back all changes made to the table since it was loaded, or the last time AcceptChanges // was called. When you copy from the database, you can lose all the data after calling RejectChanges // The ResetDataTable method rolls back one or more columns of data. private static void ResetDataTable(DataTable table, String connectionString, SqlCommand selectCommand) < using (SqlConnection connection = new SqlConnection(connectionString)) < selectCommand.Connection = connection; connection.Open(); using (SqlDataAdapter adapter = new SqlDataAdapter(selectCommand)) < // The incoming values for this row will be written to the current version of each // column. The original version of each column's data will not be changed. adapter.FillLoadOption = LoadOption.Upsert; adapter.Fill(table); >> > private static void BatchInsertUpdate(DataTable table, String connectionString, SqlCommand insertCommand, Int32 batchSize) < using (SqlConnection connection = new SqlConnection(connectionString)) < insertCommand.Connection = connection; // When setting UpdateBatchSize to a value other than 1, all the commands // associated with the SqlDataAdapter have to have their UpdatedRowSource // property set to None or OutputParameters. An exception is thrown otherwise. insertCommand.UpdatedRowSource = UpdateRowSource.None; connection.Open(); using (SqlDataAdapter adapter = new SqlDataAdapter()) < adapter.InsertCommand = insertCommand; // Gets or sets the number of rows that are processed in each round-trip to the server. // Setting it to 1 disables batch updates, as rows are sent one at a time. adapter.UpdateBatchSize = batchSize; adapter.Update(table); Console.WriteLine("Successfully to update the table."); >> > private static void ShowDataTable(DataTable table) < foreach (DataColumn col in table.Columns) < Console.Write("", col.ColumnName); > Console.WriteLine("", "RowState"); foreach (DataRow row in table.Rows) < foreach (DataColumn col in table.Columns) < if (col.DataType.Equals(typeof(DateTime))) Console.Write("", row[col]); else if (col.DataType.Equals(typeof(Decimal))) Console.Write("", row[col]); else Console.Write("", row[col]); > Console.WriteLine("", row.RowState); > > > 

См. также

  • Объекты DataAdapter и DataReader
  • Состояния и версии строк
  • AcceptChanges и RejectChanges
  • Слияние содержимого набора данных
  • Извлечение идентификации или значений автонумерации
  • Общие сведения об ADO.NET

Dataadapter c что это

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

В ADO .NET для непосредственного контакта с данными используются только обьекты Command, DataReader и иногда DataAdapter. Обьект DataAdapter — это преобразователь данных из формата DataReader в формат данных, хранимый в обьекте DataSet. Обьект DataSet — это существенно расширенный RecordSet из ADO, теперь он не контактирует с базой непосредственно. Он имеет внешний XSD-файл с описанием своей структуры и умеет напрямую читать/писать во внешние XML-файлы. Данные сначала читаются в DataReader, а уже оттуда методом FILL обьекта DataAdapter перегружаются в DataSet. В DataSet их можно посортировать и отфильтровать с помощью обьекта DataView, выполнить связывание с массивами VisualBasic или отобразить на формах с помощью обьектов DataGrid или других. А вот обратно в базу данные перегружаются методом UPDATE обьекта DataAdapter или обьектом DataCommand.

Теперь еще раз — зачем сделано так сложно и почему обьектом RecordSet из ADO или его расширенным аналогом DataSet из ADO .NET нельзя прямо читать/писать в базу. Дело в том, что SQL-сервер — штука очень универсальная, подходящая на все случаи жизни и кто работал с ней — знает — как она грузит процессор даже безо всяких ADO. А ADO полностью повторяет фунциональность SQL-сервера как в части множества различных видов курсоров, так и в части множества различных типов блокировок да еще и добавляет свою. Это получается очень сложно в плане обработки блокировок для прикладного программиста, очень сложно писать драйвера ADO для разных новых СУБД, и особенно напряжно для сервера в случае расположения курсоров всех юзеров на сервере. Плюс само ADO еще постоянно добавляет свои запросы чтобы считать схему базы данных. Короче сервер под ADO конкретно тормозит — 10 юзеров и серверному курсору — жопа. На клиентском курсоре — от силы до сотни юзеров (а DAO из Access даже на 10 юзерах просто делает что-то свое и выводится из транса только кнопкой Reset). Плюс в ADO не поддерживаются кластеры серверов, XML и многие другие современные вещи. А как же писать электронную коммерцию, интернет-магазины с миллионами корзин? Вот поэтому в ADO .NET и были отброшены все навороченные приблуды SQL и ADO (хотя иногда так приятные и удобные) и оставлен только единственный вид курсора READONLY и FORWARDONLY. Так можно делать сразу десятки тысяч коннектов к северу — и он не тормозит. Ну и конечно, второй момент кроме производительности — теперь XML органически поддерживается в .NET — и основные XML-методы добавлены именно в DataSet. Но зато теперь DataSet полностью изолирован от базы данных.

1.Чтение данных.

Для начала разберемся как выполнить самый простой запрос к базе. В любом случае первый этап — создать обьект Connections. Для этого кидаем на форму коннект с сервером из Server Explorer или со вкладки Data (но тогда надо еще настраивать ConnectionString.) При выборе же нового коннекта (которого еще нет в Server Explorer) выдается стандартное окно коннекта к базе.

  • Прочитать данные пожарным курсором — обьектом DataReader, примерно вот так.
  • Прочитать данные обьектом Command.
  • Прочитать данные обьектом DataAdtapter.

Теперь рассмотрим работу с помощью обьекта Command. Для начала надо связать обьект Command c обьектом Connections и ввести текст команды. В обьекте Command можно еще создать параметры SQL-запроса для вызова хранимой процедуры. Весь код, который создал Web-дизайнер седьмой студии из наших движений мышкой c обьектами Command и Connection можно посмотреть здесь.

  • ExecuteNonQuery — возвращает код возврата,
  • ExecuteReader — возвращает обьектDataReader с данными,
  • ExecuteScalar — возвращает число,
  • ExecuteXMLReader — возвращает XML.

т.е. собственно прога для скалярных запросов к базе с помощью обьекта Command будет выглядеть не длиннее, чем чтение DataReader‘ом:
SqlConnection1.Open()
SqlCommand1.Connection = SqlConnection1
SqlCommand1.CommandText = «select count (*) from price»
TextBox.Text = SqlCommand1.ExecuteScalar

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

  • Configure DataAdapter.
  • GenerateDataset.
  • Preview Data — Здесь вызывается мастер, который вызывает метод FILL из DataAdapter в Dataset.
  • View Schema — обработка XML-файла DataSet1.xsd.
  • Dataset Properties.

Все, что сделано этим мастером можно посмотреть в коде, созданном Дизайнером.

В принципе, Dataset довольно сложный обьект, состоящий из коллекций DataTable и DataRelation. В принципе, обьект DataTable является непосредственным аналогом обьекта RecordSet — только непосредственный контакт с данными у него отсутствует. Данные, хранимые в DataTable можно сортировать и фильтровать обьетом DataView.

В свою очередь обьект DataTable тоже имеет сложную структуру, и не только позволяет перебирать записи по RS.MoveNext, как в ADO, но и напрямую загружать/выгружать данные в XML. DataSet бывают двух типов — Typed и UnTyped. Первые хранят схему данных, из-за чего имеют подсказку в студии, доступ к полям по именам (как в АДО) и прочий сервис. Вторые никаких сервисов не имеют — но работаю на порядок быстрее. В состав студии входит специальный XML-редактор внутренннй структуры обьекта Dataset — XSD-файла. Через свойство DataSource, в котором устанавливается ссылка на обьект DataSet, визуальные компоненты .NET поддерживают привязку к данным.

2.Отображение данных.

По готовому обьекту DataSet проще всего запустить мастер отображения данных на форме. Этот мастер создает код с использованием обьекта DataGrid. Еще одна распространенная в .NET сетка для отображения данных — ComponentOne FlexGrid. Эта сетка ходит с креками на всех пиратских компактах и имеет гораздо больше возможностей, чем стандартный DataGrid от Микрософт. Кроме сетки на этих же компактах распространяется много других отличных .NET-компонентов.

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

3.Привязка данных.

Имея обьект DataSet сданными, можно выполнить отображение данных не только вручную, но с помощью привязки данных к элементам ASP-страниц, которые для этого предоставляют несколько специальных свойств. Привязку поддерживают следующие обьекты отображения данных:

  • HtmlSelect — единственный HTML-элемент, поддерживающий в .NET привязку к данным.
  • CheckBoxList.
  • DataGrid — свойства.
  • DataList — свойства.
  • Repeater.
  • DropDownList.
  • ComboBox.
  • ListBox.
  • RadioButtonList.

4.Обновление данных.

Обновления можно выполнить двумя путями — через обьект Command или через DataAdapter.

5.Сортировка и фильтрация данных.

C помощью обьекта DataView данные в DataSet можно перетусовать или отредактировать как угодно.

6.Примеры.

  • Пример проги, работающей с ADO.NET, я выложил здесь.

7.Что дает понимание ADO.NET

Написание за пару дней вот таких форм:

Работа с SqlDataAdapter и DataSet

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

Для получения данных через объект SqlDataAdapter необходимо организовать подключение к БД и выполнить команду SELECT. Есть несколько способов создания SqlDataAdapter:

SqlDataAdapter adapter = new SqlDataAdapter(); SqlDataAdapter adapter = new SqlDataAdapter(command); SqlDataAdapter adapter = new SqlDataAdapter(sql, connection); SqlDataAdapter adapter = new SqlDataAdapter(sql, connectionString);
  • Можно использовать конструктор без параметров, а команду SELECT и подключение установить позже
  • Можно передать в конструктор объект SqlCommand
  • Можно в конструкторе установить sql-выражение SELECT и объект SqlConnection
  • Можно в конструкторе установить sql-выражение SELECT и строку подключения

Рассмотрим, как получить данные в DataSet через SqlDataAdapter. Для работы с DataSet особенно удобно использовать элементы управления, которые могут заполняться из внешнего источника данных, например, DataGridView в Windows Forms. Поэтому создадим новый проект по типу Windows Forms Application.

Добавим на единственную форму в проекте элемент DataGridView и определим следующий код формы:

using System.Data; using System.Windows.Forms; using System.Data.SqlClient; namespace AdoNetWinFormsApp < public partial class Form1 : Form < public Form1() < InitializeComponent(); string connectionString = @"Data Source=.\SQLEXPRESS;Initial Catalog=usersdb;Integrated Security=True"; string sql = "SELECT * FROM Users"; using (SqlConnection connection = new SqlConnection(connectionString)) < connection.Open(); // Создаем объект DataAdapter SqlDataAdapter adapter = new SqlDataAdapter(sql, connection); // Создаем объект Dataset DataSet ds = new DataSet(); // Заполняем Dataset adapter.Fill(ds); // Отображаем данные dataGridView1.DataSource = ds.Tables[0]; >> > >

В конструкторе формы в DataGridView загружаются данные. Для загрузки данных создается объект SqlDataAdapter, который принимает объект подключения и sql-выражение SELECT. Затем создается объект DataSet и с помощью метода adapter.Fill() в него загружаются данные. Дальше происходит установка источника данных для DataGridView:

dataGridView1.DataSource = ds.Tables[0];

В качестве источника устанавливается одна из таблиц в DataSet. Каждая таблица представляет объект DataTable, и в DataSet может быть определено несколько таких таблиц. Но в данном случае при выборке в DataSet есть только одна таблица, которую мы можем получить из коллекции Tables по индексу.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *