Книги, научные публикации
Pages: | 1 | ... | 5 | 6 | 7 | 8 | 9 | ... | 11 | David Sceppa Microsoft' ADO.NET Microsoft Press Дэвид Сеппа Microsoft ADO.NET ...
-- [ Страница 7 ] --" strSQL = "SELECT OrderlD, ProductID, Quantity, UnitPrice " & "FROM [Order Details] WHERE OrderlD = 10503 " & _ "ORDER BY ProductID" en = New OleDbConnection(strConn) da = New OleDbDataAdapterCstrSQL, en) cn.0pen() ResetOrderO da.Fill(tbl) DisplayOrder("Initial contents of database") ModifyOrderO DisplayOrder("Modified data in DataSet") SubmitChangesByHand() tbl.ClearO da.Fill(tbl) DisplayOrder("New contents of database") cn.Close() End Sub ГЛАВА 10 Передача обновлений в базу данных Private Sub ModifyOrderO Dim row As OataRow row = tbl.Rows(O) row.DeleteO row = tbl.Rows{1) row("Quantity") = CType{row("Quantity"), Int16) - row = tbl.Newflow row("OrderID") = row("ProductIO") = row("Quantity") = row("UnitPrice") = 18. tbl.Rows.Add(row) End Sub Public Sub DisplayOrderfByVal strStatus As String) Dim row As DataRow Dim col As DataColumn Console.WriteLine(strStatus) Console,WriteLine(" OrderlD ProductID "& "Quantity UnitPrice") For Each row In tbl.SelectC"", "ProductID") For Each col In tbl.Columns Console.Write(vbTab & row(col) & vbTab) Next Console.WriteLineC) Next Console.WriteLinef) End Sub Private Sub ResetOrderQ Dim strSQL As String Dim cmd As OleDbComrcand = cn.CreateCommand() StrSQL = "DELETE FROM [Order Details] WHERE OrderlD = 10503" cmd.CommandText = strSQL cmd. ExecuteNonQueryO StrSQL = "INSERT INTO [Order Details] " & _ (OrderlD, ProductID, Quantity, UnitPrice) " & _ VALUES (10503, 14, 70, 23.25) " cmd.CommandText = strSQL cmd. ExecuteNonQueryO strSQL = "INSERT INTO [Order Details] " & _ (OrderlD, ProductID, Quantity, UnitPrice) " & _ VALUES (10503, 65, 20, 21.05)" cmd.CommandText = strSQL cmd. ExecuteNonQueryO End Sub Автономная работа с данными: объект DataSei модели ADO.NET 360 Часть Public Function GenTableQ As DataTable Dim tbl As New DataTable("Order Details") Dim col As DataColumn With tbl.Columns col =.Addf'OrderlD", GetType(Integer)) col.AllowDBNull = False col =.AddC'ProductID", GetType(Integer)) col.AllowDBNull = False col =.AddC'Quantity", GetType(Int16}) col.AllowDBNull = False col =.AddC'UnitPrice", GetType{Decimal}> col.AllowDBNull = False End With tbl. PrimaryKey = New DataColumnO {tbl-Columns("OrderID"), tbl.ColumnsC'ProductlD")} Return tbl End Function Visual C#.NET static OleDbConnection en;
static OleDbDataAdapter da;
static DataTable tbl;
static void Main(string[] args) { string strConn, strSQL;
strConn = "Provider=SQLOlEDB;
Data Source=(local)\\NetSDK;
" + "Initial Catalog=Northwind;
Trusted_Connection=Yes;
";
strSQL = "SELECT OrderlD, ProductID, Quantity, UnitPrice " + "FROM [Order Details] WHERE OrderlD = 10503 " + "ORDER 8Y ProductID";
en = new OleDbConnection(strConn);
da = new 01eDbOataAdapter(strSQL, en);
tbl = GenTablef);
cn.OpenQ;
ResetOrderQ;
da.Fill(tbl);
DisplayOrder("Initial contents of database");
ModifyOrderO;
DisplayOrder("Modified contents of DataSet");
SubmitChangesByHand();
tbl.ClearO;
da.Fill(tbl);
DisplayOrderC'New contents of database");
cn.Close();
static void ModifyOrderO ГЛАВА 10 Передача обновлений в базу данных DataRow row;
row = tbl.Rows[0];
row.DeleteC);
row = tbl.Rows[1];
row["Quantity"] = (Int16) row["Quantity"] row = tbl.NewRowQ;
row["OrderID"] = 10503;
row["ProductID"] = 1;
rowf'Quantity"] = 24;
row["UnitPrice"] = 18.0;
tbl, Rows. Add(row);
static void DisplayQrder(string strStatus) { Console, WriteLine( strStatus);
Console. WriteLinef" OrderlD ProductID "+.Х "Quantity UnitPrice");
fo reach (DataRow row in tbl.Select("", "ProductID")) { foreacri(DataColurnn col in tbl. Columns) Console, Write("\t" + row[col] + "\t");
Console. WriteLineO;
} Console. WriteLineO;
static void ResetOrderC) < string strSQL;
OleDbCommand cmd = cn.CreateCommandO;
strSQL = "DELETE FROM [Order Details] WHERE OrderlO = 10503' cmd.CommandText = strSOL;
cmd. ExecuteNonQue ry( ) ;
strSOL = "INSERT INTO [Order Details] " + (OrderlD, ProductID, Quantity, UnitPrice) " + VALUES (10503, 14, 70, 23.25) " cnd.CommandText = strSQL;
cmd. ExecuteNonQue ry();
StrSQL = "INSERT INTO [Order Details] " + (OrderlD, ProductID, Quantity, UnitPrice) " + VALUES (10503, 65, 20, 21.05)";
cmd.CommandText = strSQL;
cmd. ExecuteNonQue ry();
static DataTable GenTableQ 1 3- Часть 111 Автономная работа с данными: объект DataSet модели ADO.NET DataTable tbl = new DataTable("Order Details");
DataColumn col;
col = tbl.Columns.Add("Order-ID", typeof(int));
col.AllowDBNull = false;
col = tbl.Columns.Add("ProductID", typeof(int));
col.AllowDBNull = false;
col = tbl.Columns.Add("Quantity", typeof(Int16));
col.AllowDBNull = false;
col = tbl.Columns.Add("UnitPrice", typeof(Decimal));
col.AllowDBNull = false;
tbl.PrimaryKey = new DataColumn[] {tbl.Columns["OrderID"], tbl.ColumnspProductlD"]};
return tbl;
!
Мы только что написали большой объем кода для передачи отложенных из менений. Код, на основе которого генерируются параметризованные объекты Command, уникален для исходного запроса. Тем не менее код процедуры Submit CbangesByHand универсален. Он просматривает каптированные изменения в объек те DataTable, определяет, как именно изменены объекты DataRow, вызывает фун кцию, выполняющую запрос для передачи отложенного изменения, и затем, в зависимости от возвращенного значения функции, соответствующим образом помечает объект DataRow.
По существу, мы воссоздали функциональность обновления, предоставляемую объектом DataAdapter. Подробнее о нем Ч ниже.
Передача обновлений с использованием объектов DataAdapter ADO.NET В главе 5 рассказывалось об использовании объекта DataAdapter для записи ре зультатов запросов в объекты DataTable. но это лишь половина функциональнос ти DataAdapter. Данный объект также предназначен для передачи отложенных изменений из объектов DataSet, Чтобы создать логику обновления, используемую объектами DataAdapter для передачи изменений в БД, можно:
Х вручную программно сконфигурировать объекты DataAdapter, Х воспользоваться в период выполнения объектом CommandBuilder.
Х воспользоваться в период разработки мастером Data Adapter Configuration Wizard.
У каждого из этих способов есть свои преимущества и недостатки, которые я подробно разберу далее.
Конфигурирование объектов DataAdapter вручную Объект DataAdapter предоставляет четыре свойства, содержащих объекты Command.
Как вы помните, свойство SelectCommand содержит объект Command, при помо щи которого DataAdapter заполняет ваш объект DataTable. Три остальных свой ГЛАВА 10 Передача обновлений в базу данных ства, UpdateCommand, InsertCommand и DeleteCommand, содержат объекты Com mand, при помощи которых DataAdapter передает отложенные изменения.
Такая архитектура сильно отличается от объектной модели ADO. Волшебная технология черный ящик* больше не используется. Вы управляете тем, как Data Adapter передает отложенные изменения, поскольку предоставляете используемые им объекты Command.
Метод Update объекта DataAdapter очень гибок и принимает объект DataSet, DataSet и имя таблицы, объект Data-Table или массив объектов DataRou*. Незави симо от того, как вызван метод DataAdaplerUpdate, DataAdapter попытается пере дать отложенные изменения при помощи соответствующего объекта Command.
Всю работу, выполнявшуюся нами ранее с помощью процедуры SubmitCbangesBy Hand, удается выполнить посредством одного вызова метода DataAdapter.Update.
Связанные параметры Созданная нами процедура SubmtiCbangesByHana'не особенно сложна. Кроме того, она выполняет не слишком много работы. Вместо этого процедура делегирует ее одной из трех функций: SubmitUpdate, Submitlnsert или SubmilDelele. Эти функции на основании содержимого измененной записи подставляют в соответствующий запрос значения параметров.
Для передачи отложенных изменений с использованием DataAdapter приме няются такие же параметризованные запросы.
UPDATE [Order Details] SET OrderlD = ?, ProductID = ?, Quantity = ?, UnitPrice = ?' WHERE OrderlD = ? AND ProductID = ? AND Quantity = ? AND UnitPrice = ?
INSERT INTO [Order Details] (OrderlD, ProductID, Quantity, UnitPrice) VALUES (?, ?, ?, ?) DELETE FROM [Order Details] WHERE OrderlD = ? AND ProductID = ? AND Quantity = ? AND UnitPrice = ?
Тем не менее при добавлении параметров в объекты Command, хранящиеся в свойствах объекта DataAdapter, мы используем два свойства объекта Parameter ADO.NET. предназначенные специально для обновлений на основе DataAdapter:
SourceColumn и SourceVersion.
По сути, эти свойства связывают объект Parameter с объектом DataColumn из состава Data-Table. Перед выполнением запроса DataAdapter на основе данных свойств определяет, какое значение задать свойству Value объекта Parameter, ана логично тому, как это осуществлялось в функциях SubmitUpdate, Submitlnsert и SubmitDelete. Подробнее Ч на рис. 10-2.
Следующий фрагмент кода не только создает параметризованные объекты Command, но и задает значения свойств SourceColumn it SourceVersion объектов Parameter. Значение свойства по умолчанию SourceVersion Ч DataRouVersion.Current, и задавать его следует, только если объект Parameter требуется связать с ориги нальными значениями нужного столбца.
Часть III Автономная работа с данными: объект DataSet модели ADO.NET Quantity ProductiD LJnitPrice OrderlD DstaRow 10503 65 21. (текущая версия) UPDATE [Order Details] \ \ ^я SET OrcterlD = ?, ProductiD = ?, Quantity = ?, UnitPrice = ?
WHERE OrderlD = ? AND ProductiD = ? AND Quantity = ? AND UnitPrice = ?
DataRow 10503 65 40 21. (оригинальная версия) QrderiD ProductlD Quantity UnitPrice Рис. 10-2. Связывание объектов Parameter с объектами DataColumn Visual Basic.NET Private Function CreateDataAdapterUpdateCommandO As OleDbCommand Dim strSQL As String strSQL = "UPDATE [Order Details] " & _ SET OrderlD = ?, ProductiD = ?, " & _ Quantity = ?, UnitPrice = ? " & _ WHERE OrderlD = ? AND ProductiD = ? AND " & _ Quantity = ? AND UnitPrice = ?" Dim cmd As New QleDbCommandCstrSQL, en) Dim pc As OleDbParameterCollection = cmd.Parameters pc.Add("OrderID_New", OleDbType.Integer, 0, "OrderlD") pc.Add("ProductIDJIew", OleDbType.Integer, 0, "ProductiD"} pc.Add("Quantity_New", OleDbType.Smalllnt, 0, "Quantity") pc.Add("UnitPrice_New", OleDbType.Currency, 0, "UnitPrice") Dim param As OleDbParameter param = pc.Add("OrderID_Orig", OleDbType.Integer, 0, "OrderlD") param.SourceVersion = DataRowVersion.Original param = pc.Add("ProductIDJ3rig", OleDbType.Integer, 0, "ProductiD").
param.SourceVersion = DataRowVersion.Original param = pc.Add("Quantity_Orig", OleDbType.Smalllnt, 0, "Quantity") param.SourceVersion = DataRowVersion.Original param = pc.Add("UnitPrice_Orig", OleDbType.Currency, 0, "UnitPrice") param.SourceVersion = DataRowVersion.Original Return cmd End Function Private Function CreateDataAdapterlnsertCommandO As OleDbCommand ГЛАВА 10 Передача обновлений в базу данных Dim strSQL As String strSQL = "INSERT INTO [Order Details] " & _ (OrderlD, ProductID, Quantity, UnitPrice) " & VALUES (?, ?, ?, ?)" Dim cmd As New OleDbCommandCstrSQL, on) Dim pc As OleDbParameterCollection = cmd.Parameters pc.Add("OrderlD", OleDbType.Integer, 0, "OrderlD") pc.Add("ProductID", OleDbType.Integer, 0, "ProductID") pc.Add("Quantity", OleDbType.Smalllnt, 0, "Quantity") pc.Add("UnitPrice", OleDbType.Currency, 0, "UnitPrice") Return cmd End Function Private Function CreateDataAdapterDeleteCommand() As OleDbCommand Dim strSQL As String StrSQL = "DELETE FROM [Order Details] " & _ WHERE OrderlD = ? AND ProductID = ? AND " & _ Quantity = ? AND UnitPrice = ?" Dim cmd As New 01eDbCommand(strSQL, en) Dim pc As OleDbParameterCollection = cmd.Parameters Dim param As QleDbParatneter pc.Add("OrderID", OleDbType.Integer, 0, "OrderlD") param.SourceVersion = DataRowVersion.Original pc.AddC'ProductID", OleDbType.Integer, 0, "ProductID") param.SourceVersion = DataRowVersion.Original pc.Add("Quantity", OleDbType.Smalllnt, 0, "Quantity") param.SourceVersion = DataRowVersion.Original pc.Add("UnitPrice", OleDbType.Currency, 0, "UnitPrice") pa ram.SourceVersion = DataRowVersion.Original Return cmd End Function Visual C#.NET static OleDbCommand CreateDataAdapterUpdateCommandO { string strSQL;
StrSQL = "UPDATE [Order Details] " & _ SET OrderlD = ?, ProductID = ?, " + Quantity = ?, UnitPrice = ? " + WHERE OrderlD = ? AMD ProductIO = ? AND " + Quantity = ? AND UnitPrice = ?";
OleDbCommand cmd = new 01eDbCommand(strSQL, en);
OleDbParameterCollection pc = cmd.Parameters;
pc.Add("OrderID_New", OleDbType.Integer, 0, "OrderlD");
366 Часть 111 Автономная работа с данными: объект DataSet модели ADO. NET pc.Add("ProductID_New", OleDbType. Integer, 0, "ProductID");
pc.Add("Quantity_New", OleDbType. Smalllnt, 0, "Quantity");
pc. Add("UnltPrice_New", OleDbType. Currency, 0, "Unit Price");
OleDbParameter param;
param = pc.Add("Order!D_Orig", OleDbType. Integer, 0, "OrderlD");
param. SourceVersion = DataRowversion. Original;
param = pc.Add("ProductID_Orig", OleDbType. Integer, 0, "ProductID");
param. SourceVersion = DataRowversion. Original;
param = pc.Add("Ouantity_Orig", OleDbType. Smalllnt, 0, "Quantity");
param. SourceVersion = DataRowversion. Original;
param = pc.Add("UnitPrice_Orig", OleDbType. Currency, 0, Х'UnitPrice");
param. SourceVersion = DataRowversion. Original;
return cmd;
static OleDbCommand CreateDataAdapterInsertCommand( ) i string strSQL;
strSQL = "INSERT INTO [Order Details] " + (OrderlD, ProductID, Quantity, UnitPrice) " + VALUES {?, ?, ?, ?)";
OleDbCommand cmd = new OleDbComniancKstrSQL, en);
OleDbParameterCollection pc = cmd. Parameters;
pc,Add("OrderID", OleDbType. Integer, 0, "OrderlD");
pc.Add("ProductID", OleDbType. Integer, 0, "ProductID");
pc.Add( "Quantity". OleDbType. Smalllnt, 0, "Quantity");
pc.Add( "Unit Price", OleDbType. Currency, 0, "UnitPrice");
return cmd;
i static OleDbCommand CreateOataAdapterDeleteCommandO { string strSQL;
strSQL = "DELETE FROM [Order Details] " + WHERE OrderlD = ? AND ProductID = ? AND " + Quantity = ? AND UnitPrice = ?";
OleDbCommand cmd = new 01eDbCommand(strSQL, en);
OleDbParameter param;
OleDbParameterCollection pc = cmd. Parameters;
param = pc.Add( "OrderlD", OleDbType. Integer, 0, "OrderlD");
param. SourceVersion = DataRowversion. Original;
param = pc.AddC'ProductID", OleDbType. Integer, 0, "ProductID");
ГЛАВА 10 Передача обновлений в базу данных param.SourceVersion = DataRowVersion. Original;
param = pc.Add("Quantity", QleDbType.Smalllnt, 0, "Quantity");
param.SourceVersion = DataRowVersion. Original;
param = pc.AddC'UnitPrtce", OleDbType. Currency, 0, "UnitPrice");
param.SourceVersion = DataRowVersion. Original;
return cmd;
} Теперь процедуры SubmttChangesByHand, SubmitUpdate, Siibmittnsert и SubmitDt-lete можно заменить следующим кодом;
Visual Basic.NET Private Sub SubmitChangesViaDataAdapter() da.UpdateCommand = CreateDataAdapterUpdateCommandQ da. InsertCommand = CreateDataAdapterlnsertCommandO da.DeleteCommand = CreateDataAdapterDeleteCommandO da.Update(tbl) End Sub Visual C#.NET static void SubmitChangesViaDataAdapterO { da.UpdateCommand = CreateDataAdapterUpdateCommandO;
da. InsertCommand = CreateDataAdapterlnsertCommandO;
da.DeleteCommand = CreateDataAdapterDeleteCommandO;
da.Update(tbl);
Передача обновлений с использованием хранимых процедур Одна из наиболее частых жалоб разработчиков, получавших данные из БД сред ствами ADO, Ч невозможность использования метода Recordset.UpdateBatch для передачи обновлений при помощи хранимых процедур.
Как уже говорилось, DataAdapter позволяет вам определить собственную ло гику обновления. В приведенных ранее фрагментах кода показано, как создать собственные объекты Command, с помощью которых DataAdapter будет переда вать отложенные изменения в БД. Аналогичный код годится и для передачи об новлений средствами хранимых процедур.
Во-первых, в БД Northwind следует определить хранимые процедуры, позво ляющие изменять, вставлять и удалять записи таблицы Order Details. Для созда ния процедур, которые будут вызываться в нашем коде, скопируйте и выполните следующий фрагмент кода в SQL Server Query Analyzer. Если у вас установлено только ядро MSDE и, как следствие, нет доступа к SQL Server Query Analyzer, вызовите процедуру CreateSprocs (приводится в одном из последующих фрагментов кода) и создайте нужные хранимые процедуры.
Автономная работа с данными: объект DataSet модели ADO.NET 368 Часть USE Northwind GO CREATE PROCEDURE spUpdateDetail (@OrderID_New int, @ProductID_New int, @Quantity_New smallint, @UnitPrice_New money, @OrderID_Orig int, @ProductID_Orig int, @Quantity_Orig smallint, @UnitPrice_Qrig money) AS UPDATE [Order Details] SET OrderlD = @OrderlD_New, ProductID = @ProductID_New, Quantity = @Quantity_New, UnitPrice = @UnitPrice_New WHERE OrderlD = @OrderID_Orlg AND ProductID = @ProductID_Orig AND Quantity = @Quantity_Orig AND UnitPrice = 3UnitPrice_Orig GO CREATE PROCEDURE spInsertDetail (@OrderID int, gProductlD int, ^Quantity smallint, ^UnitPrice money) AS INSERT INTO [Order Details] (OrderlD, ProductID, Quantity, UnitPrice) VALUES (@OrderID, 0ProductID, ^Quantity, @UnitPrice) GO CREATE PROCEDURE spDeleteDetail (@OrderID int, ^ProductID int, йQuantity smallint, йUnitPrice money) AS DELETE FROM [Order Details] WHERE OrderlD = @OrderID AND ProductID = зProductID AND Quantity = ^Quantity AND UnitPrice = йUnitPrice Имея хранимые процедуры для передачи обновлений в таблицу Order Details, можно написать объекты Command, автоматически вызывающие их при вызове метода DataAdapter.Update.
Следующий фрагмент кода включает функции, которые создают объекты Com mand, содержащие вызовы приведенных выше процедур. Кроме того, он включа ет процедуру для создания всех этих хранимых процедур в БД. Все, что остается сделать для передачи обновлений с помощью хранимых процедур Ч связать наши новые объекты Commands объектом DataAdapter. Это осуществляется в процеду ре SubmitCbangesViaStoredProcedures.
Visual Basic.NET Private Sub SubmitChangesViaStoredProceduresO da.UpdateCommand = CreateUpdateViaSPComraandO da.InsertCommand = CreatelnsertViaSPCommandO ГЛАВА 10 Передача обновлений в базу данных da.DeleteCommand = CreateDeleteViaSPCommandQ da.Update(tbl) End Sub Private Function CreateUpdateViaSPCommandO As OleDbCommand Dim cmd As New 01eDbCommand("spUpdateDetail", en) cmd.CommandType = CommandType.StoredProcedure Dim pc As OleDbParameterCollection = cmd.Parameters pc.Add("OrderlD_New", OleDbType.Integer, 0, "OrderlD") pc.Add("ProductID_New", OleDbType,Integer, 0, "ProductID") pc.Add("Quantity_New", OleDbType.Smalllnt, 0, "Quantity") pc.Add("UnitPrice_New", OleDbType.Currency, 0, "UnitPrice") Dim param As OleDbParameter param = pc.Add("OrderID_Orig", OleDbType.Integer, 0, "OrderlD") param.SourceVersion = DataRowVersion.Original param = pc.Add("ProductID_Orig", OleDbType,Integer, 0, "ProductID") param.SourceVersion = DataRowVersion.Original param = pc.Add("Quantity_Orig". OleDbType.Smalllnt, 0, "Quantity") pa ram.SourceVersion = DataRowVersion.Original param = pc.Add("UnitPrtce_Orig", OleDbType.Currency, 0.
"UnitPrice") param.SourceVersion = DataRowVersion.Original Return cmd End Function Private Function CreatelnsertViaSPCommandO As OleDbCommand Dim cmd As New OleDbCommandC'spInsertDetail", en) cmd.CommandType = CommandType.StoredProcedure Dim pc As OleDbParameterCollection = cmd.Parameters pc.AddC"OrderlD", OleDbType.Integer, 0, "OrderlD") pc.Add("ProductID", OleDbType.Integer, 0, "ProductID") pc.Addt"Quantity", OleDbType.Smalllnt, 0, "Quantity") pc.Add("UnitPrice", OleDbType.Currency, 0, "UnitPrice") Return cmd End Function Private Function CreateDeleteViaSPCommandO As OleDbCommand Dim cmd As New 01eDbCommand{"spDeleteDetail", on) cmd.CommandType = CommandType.StoredProcedure Dim pc As OleDbParameterCollection = cmd.Parameters Dim param As OleDbParameter param = pc.Add("OrderID", OleDbType.Integer, 0, "OrderlD") Автономная работа с данными: объект DataSet модели ADO.NET 370 Часть III param.SourceVersion = DataRowVersion.Original param = pc.Add("ProductID", OleDbType.Integer, 0, "ProductlD") param.SourceVersion = DataRowVersion.Original param = pc.AddC"Quantity", OleDbType,Smalllnt, 0, "Quantity") param.SourceVersion = DataRowVersion.Original param = pc.Add("UnitPrice", OleDbType.Currency, 0, "UnitPrice") param.SourceVersion = DataRowVersion.Original Return cmd End Function Private Sub CreateSprocsO Dim cmd As OleDbCommand = cn.CreateComrnand Dim strSQL As String strSQL = "CREATE PROCEDURE spUpdateDetail " & vbCrLf & _ (@OrderID_New int, @ProductID_New int, " & vbCrLf & _ @Quantity_New smallint, " & vbCrLf & @UnitPrice_New money, " & vbCrLf & @OrderID_Orig int, " & vbCrLf & _ @ProductID_Orig int, " & vbCrLf & @Quantity_Orig smallint, " & vbCrLf & @UnitPrice_Orig money) " & vbCrLf & "AS " & vbCrLf & _ "UPDATE [Order Details] " & vbCrLf & _ SET OrderlD = @OrderID_New, " & vbCrLf & _ ProductlD = @ProductID_New, " & vbCrLf & _ Quantity = @Quantity_New, " & vbCrLf & _ UnitPrice = @UnitPrice_New " & vbCrLf & WHERE OrderlD = @OrderID_Qrig AND " & vbCrLf &_ ProductlD = @ProductID_Orig AND " & vbCrLf & Quantity = @Quantity_Orig AND " & vbCrLf UnitPrice = @UnitPrice_Orig" cmd.ConnnandText = strSQL cmd. ExecuteNonQueryO strSQL = "CREATE PROCEDURE spInsertDetail " & vbCrLf & _ (@OrderID int, @ProductID int, " & vbCrLf & _ ^Quantity smallint, ^UnitPrice money) " & vbCrLf & "AS " & vbCrLf & _ "INSERT INTO [Order Details] " & vbCrLf & _ (OrderlD, ProductlD, Quantity, UnitPrice} " & vbCrLf & _ VALUES (@OrderID, @ProductID, ^Quantity, @UnitPrice)" cmd.CommandText := strSQL end. ExecuteNonQueryO strSQL = "CREATE PROCEDURE spDeleteDetail " & vbCrLf & _ (йOrderlD int, йProductld int, " & vbCrLf & ^Quantity smallint, @UnitPrice money) " & vbCrLf & "AS " & voCrLf & Передача обновлений в базу данных ГЛАВА "DELETE FROM [Order Details] " & vbCrLf & _ WHERE OrderlD = @OrderID AND " & vbCrLf & _ ProductID = @ProductID AND " & vbCrLf & Quantity = ^Quantity AND UnitPrice = @UnitPrice" cmd.CommandText = strSQL cmd. ExecuteNonQueryC ) End Sub Visual C#.NET static void SubmitChangesViaStoredProcedu res( ) { da.UpdateCommand = CreateUpdateViaSPCommandO;
da.InsertCommand = CreatelnsertViaSPCommandO;
da.DeleteComrnand = CreateDeleteViaSPCommandO;
da.Update(tbl);
static OleDbCommand CreateUpdateViaSPCommandO { OleDbCommand cmd = new OleDbCommandC'spUpdateDetail", en);
cmd. CommandType = CommandType. StoredProcedure;
OleDbParameterColLection pc = cmd. Parameters;
pc.Add("OrderID_New", OleObType. Integer, 0, "OrderlD");
pc.Add( "Product ID_New", OleDbType. Integer, 0, "ProductID");
pc.Add("Guantity_New", OleDbType. Smalllnt, 0, "Quantity");
pc.Add("UnitPrice_New", OleDbType. Currency, 0, "UnitPrice");
OleDbParameter param;
param = pc.Add("OrderID_Orig", OleDbType. Integer, 0, "OrderlD");
param. SourceVersion = DataRowVersion. Original;
param = pc.Add("ProductID_Orig", OleDbType. Integer, 0, "ProductID");
param. SourceVersion = DataRowVersion. Original;
param = pc.Add("Quantity_Orig", OleDbType. Smalllnt, 0, "Quantity");
param. SourceVersion = OataRowVerston. Original;
param = pc.Add( "Unit Price_0 rig", OleDbType. Currency, 0, "UnitPrice");
param. SourceVersion = DataRowVersion. Original;
return cmd;
static OleDbCommand CreatelnsertViaSPCommandO i OleDbCommand cmd = new OleDbCommandC'spInsertDetaiL", en);
cmd.CommandType = CommandType. StoredProcedure;
OleDbPararrteterCollection pc = cmd. Parameters;
pc.Add("OrderrD", OleDbType. Integer, 0, "OrderlD");
pc.Add("ProductID", OleDbType. Integer, 0, "ProductID");
372 Часть III Автономная работа с данными: объект DataSet модели ADO.NET рс.Add("Quantity", OleDbType.Smalllnt, 0, "Quantity"};
pc.Add("UnitPrice", OleDbType.Currency, 0, "UnitPrice");
return cmd;
) static OleDbCommand CreateDeleteViaSPCommandO { OleDbCommand cmd = new OleDbCoromandC'spDeleteDetail", en);
cmd.CommandType = CommandType.StoredProcedure;
OleDbParameterCollection pc = cmd.Parameters;
OLeDbParameter param;
param = pc.Add("Order!D", OleDbType.Integer, 0, "QrderlD");
param.SourceVersion = DataRowVersion,Original;
param = pc.Add("ProductID", OleDbType.Integer, 0, "ProductID");
param.SourceVersion = DataRowVersion.Original;
param = pc,Add{"Quantity", OleDbType.Smalllnt, 0, "Quantity");
param.SourceVersion = DataRowVersion.Original;
param = pc.Add("UnitPrice", OleDbType.Currency, 0, "UnitPrtce");
param.SourceVersion = DataRowVersion.Original;
return cmd;
} static void CreateSprocsQ { OleDbCommand cmd = cn.CreateCommandC);
string strSQL;
strSQL = "CREAJE PROCEDURE spUpdateDetail \n\r" + (@OrderID_New int, @ProductID_New int, \n\r" + @Quantity_New smallint, @UnitPrice_New money, \n\r" + @OrderID_Orig int, @ProductID_Orig int, \n\r" + @Quantity_Orig smallint, @UnitPrice_Orig money) \n\r" + "AS \n\r" + "UPDATE [Order Details] \n\r" + SET OrderlD = @OrderID_New, \n\r" + ProductID = @ProductIDjJew, \n\r" + Quantity = @Quantity_New, \n\r" + UnitPrice = @UnitPrice_New \n\r" + WHERE OrderlD = @QrderID_Orig'AND \n\r" + ProductID = @ProductID_Orig AND \n\r" + Quantity = @Quantity_Orig AND \n\r" + UnitPrice = @UnitPrice_Orig";
cmd.CommandText = strSQL;
cmd.ExecuteNonQueryO;
strSQL = "CREATE PROCEDURE spInsertDetail \n\r" + C^OrderlD int, йProductID int, \n\r" + ГЛАВА 10 Передача обновлений в базу данных ^Quantity smallint, @UnitPrice money) \n\r" + "AS \n\r" + "INSERT INTO [Order Details] \n\r" + (OrderlD, ProductID, Quantity, UnitPrice) \n\r" + VALUES (@OrderID, &ProductID, ^Quantity, @>UnitPrice)";
cmd.CommandText = strSQL;
cmd.ExecuteNonQuery();
strSQL = "CREATE PROCEDURE spDeleteDetail \n\r" + (@OrderID int, @ProductID int, \n\r" + ^Quantity smallint, @UnitPrice money) \n\r" + "AS \n\r" + "DELETE FROM [Order Details] \n\r" + WHERE OrderlD = @OrderID AND \n\r" + ProductID = @ProductID AND \n\r" + Quantity = йQuantity AND UnitPrice = @UnitPrice' crnd. CommandText = strSOL;
cmd.ExecuteNonQue ry();
Использование собственной логики обновления Рассмотрим преимущества и недостатки применения собственной логики обнов ления в коде.
Преимущества Два важнейших преимущества использования собственной логики обновления в коде Ч расширенные возможности управления и производительность. По срав нению с предыдущими технологиями доступа к данным Microsoft, объект Data Adapter ADO.NET предоставляет самые широкие возможности управления. Исчез ло требование передавать обновления непосредственно в таблицы;
наконец-то стало возможно быстро и эффективно использовать хранимые процедуры.
Кроме того, поскольку вы не определяете происхождение данных с помощью технологии доступа к данным, можно считать, что любой набор результатов под держивает обновление. Когда ядро курсоров ADO не умело собрать метаданные, необходимые для передачи изменений в БД, предоставить такие данные программ но было нельзя. В ADO.NET объект DataSet разрешается заполнять результатами вызова хранимой процедуры, запроса к временной таблицы, сводными результа тами множества запросов или любым другим удобным для вас способом, и вы все равно сможете передать изменения в БД.
Предоставление логики обновления в коде повышает производительность приложения. Во фрагменте кода, передававшем обновления в БД с помощью дра курсоров ADO, меньше строк, однако ядру приходилось получать из БД имя ис ходной таблицы, исходных столбцов, а также сведения о первичном ключе ис ходной таблицы. На получение метаданных из системных таблиц БД и генера цию логики обновления на их основе требуется больше времени, чем на загрузку та ких данных из локального кода.
Автономная работа с данными: объект DataSet модели ADO.NET 374 Часть III Недостатки Недостатки использования собственной логики обновления в коде Ч зеркальное отражение преимуществ ядра курсоров ADO. Во-первых, собственная логика об новления занимает больше места. Вернитесь назад и посмотрите, сколько кода требуется для передачи обновлений с использованием объекта DataAdapter ADO.NET и сколько Ч для передачи с использованием ядра курсоров ADO. Написание та кого кода Ч утомительное занятие, отнимающее много времени.
Еще один недостаток в том, что при создании собственной логики обновле ния многие разработчики чувствуют 1 себя неуверенно. Им хотелось бы не зада вать вопросов типа Нужно ли взять имя таблицы в запросе в символы-раздели тели?, Какие маркеры параметров использовать?, <Х Какие столбцы использовать в разделе WHERE запросов UPDATE и DELETE?, Каково наиболее подходящее значение свойства OleDbType для параметра, содержащего значение дата/время? К счастью, если более быстрые способы создания логики обновления. Подробнее о них Ч далее в этой главе.
Создание логики обновления с помощью объекта CommandBuilder Объектная модель ADO.NET позволяет вам не только определить собственную логику обновления, но и предоставляет средства динамической генерации такой логики с использованием объекта CommandBuilder, по аналогии с ядром курсо ров ADO. Если создать экземпляр CommandBuilder и сопоставить его с объектом DataAdapter^ CommandBuilder попытается сгенерировать логику обновления на основе запроса, хранящегося в свойстве SelectCommand объекта DataAdapter.
Чтобы продемонстрировать принципы работы объекта CommandBuilder, я с его помощью сгенерирую логику обновления для кода, выполняющего запросы к таб лице Order Details. Следующий фрагмент создает экземпляр объекта OleDhCom mandBuilder, передавая в конструкторе объект OleDbDataAdapter. Затем он выво дит запрос, хранящийся в свойстве InsertCommand и сгенерированный объектом CommandBuilder для передачи новых записей.
Visual Basic.NET Dim strConn, strSQL As String strConn = "Provider=SQLOLEDB;
Data Source=(local)\NetSDK;
" & _ "Initial Catalog=Northwind;
Trusted_Connection=Yes;
" strSQL = "SELECT OrderlD, ProductlD, Quantity, UnitPrice " & _ "FROM [Order Details] WHERE OrderlD = 10503 " i _ "ORDER BY ProductlD" Dim da As New 01eDbDataAdapter(strSQL, strConn} Dim cb As New OleDbCommandBuilder(da) Console.WriteLine(cb,GetInsertCommand.CommandText) Visual C#.NET string strConn, strSQL;
strConn = "Provider=SQLOLEDB;
Data Source=(local)\\NetSDK;
" + "Initial Catalog=Northwind;
Trusted_Connection=Yes;
";
Передача обновлений в базу данных ГЛАВА strSQL = "SELECT OrderlD, ProductID, Quantity, UnitPrice " + "FROM [Order Details] WHERE OrderlD = 10503 " + "ORDER BY ProductID";
OleDbDataAdapter da = new 01eDbDataAdapter(strSQL, strConn);
OleDbCommandBuilder cb = new OleDbCommandBuiLder(da);
Console.WriteLine(cb.GetInsertCommand().CommandText);
Как видно, текст запроса довольно сильно походит на запросы, создававшие ся нами в предыдущих разделах главы для передачи новых записей:
INSERT INTO Order Details( OrderlD, ProductID, Quantity, UnitPrice ) VALUES ( ?, ?, ?, ? ) Как объект CommandBuilder генерирует логику обновления Логика, на основе которой CommandBuilder генерирует запросы UPDATE, INSERT и DELETE, не представляет собой ничего сложного. Как и ядро курсоров ADO.
CommandBuilder обращается к БД за именами базовой таблицы и столбцов, а так же за сведениями о ключевых столбцах набора результатов запроса. Объект Com mandBuilder сгенерирует логику обновления, если выполняются все следующие условия:
Х запрос возвращает данные только из одной таблицы;
Х на таблице определен первичный ключ;
Х первичный ключ есть в результатах вашего запроса.
Как уже говорилось, первичный ключ гарантирует, что CommandBuilder обно вит: не более одной записи. Почему объект CommandBuilder налагает ограниче ние на число таблиц, упомянутых в результатах запроса? Подробнее об этом Ч в следующих разделах главы.
CommandBuilder выбирает метаданные, необходимые для генерации логики обновления, с использованием свойства SelectCommand объекта DataAdapter, На самом деле об этом уже говорилось вкратце в главе 4- Метод ExecuteReader объек та Command позволяет получить эти метаданные вместе с результатами запроса, как показано ниже:
Visual Basic.NET Dim strConn, strSQL As String StrConn = "Provider=SQLOLEDB;
Data Source=(local)\NetSDK;
" & "Initial Catalog=Northwind;
Trusted_Connection=Yes;
" strSQL = "SELECT OrderlD, ProductID, Quantity, UnitPrice " & _ "FROM [Order Details] WHERE OrderlD = 10503 " & _ "ORDER BY ProductID" Dim en As New OleDbConnection(strConn) Dim cmd As New 01eDbCommand(strSQL, en) cn.0pen{) Dim rdr As OleDbDataReader rdr = cmd.ExecuteReader(CommandBehavior.SchemaOnly Or _ ComtnandBehavior.Keylnfo) Dim tbl As DataTable = rdr.GetSchemaTable rdr.Closef) 376 Часть III Автономная работа с данными: объект DataSet модели ADO.NET cn.CloseO Dim row As DataRow Dim col As DataColumn For Each row In tbl.Rows For Each col In tbl.Columns Console.WriteLineCcol.ColumnNarne & ": " & row(col).ToString) Next col Console. Writel_ine() Next row Visual C#.NET string strConn, strSQL;
strConn = "Provider=SQLOLEDB;
Data Source=(local)\\NetSDK;
" + "Initial Catalog=Northwind;
Trusted_Connection=Yes;
";
strSQL = "SELECT OrderlD, ProductlD, Quantity, UnitPrice " + "FROM [Order Details] WHERE OrderlD = 10503 " + "ORDER BY ProductlD";
OleDbConnection en = new OleDbConnection(strConn);
OleDbCommand cmd = new 01eDbCominand{strSQL, en);
cn.OpenO;
OleDbDataReader rdr;
rdr = cmd.ExecuteReader(CommandBehavior,SchemaOnly | CommandBehavior.Keylnfo);
DataTable tbl = rdr.GetSchemaTableO;
rdr.Close();
cn.CloseO;
foreach (DataRow row in tbl.Rows) { foreach {DataColumn col in tbl.Columns) Console.WriteLine(col.ColumnName + ": " + row[col].ToStringQ);
Console. WriteLineO;
' Запустив этот код, вы увидите все данные, которыми объект CommandButt der должен обладать о каждом столбце, чтобы сгенерировать логику обновления.
Имя столбца? Имена базовой таблицы и базового столбца для данного столбца?
Является ли столбец частью первичного ключа базовой таблицы? Содержит ли столбец большой объем текстовых или двоичных данных? И т.д., и т.п.
Преимущества и недостатки использования объекта CommandBuilder Сравнив фрагмент кода, сгенерированный объектом CommandBuilder, и код, на основе которого мы создавали собственную логику обновления, вы выявите два основных преимущества использования объекта CommandBuilder. Во-первых, требуется меньше кода. Во-вторых, с помощью CommandBuilder удается создавать ГЛАВА 10 Передача обновлений в базу данных логику обновления, имея даже поверхностное представление о SQL-синтаксисе запросов UPDATE, DELETE и INSERT.
Кроме того, объект CommandBuilder полезен, если у вас возникли проблемы с генерацией собственной логики обновления. Если CommandBuilder успешно сге нерирует необходимую логику, просмотрите значение свойства CommandText созданных им объектов Command или значения свойств созданных им объектов Parameter.
Объект CommandBuilder также весьма полезен в приложениях, которым тре буется поддержка обновления данных и в которых вы не хотите просматривать структуру запросов в период разработки.
Как и ядро курсоров ADO, объект CommandBuilder автоматически генерирует для вас логику обновления в период выполнения. Таким образом, он подвержен тем же проблемам и ограничениям, что и ядро курсоров ADO.
Объект CommandBuilder не предоставляет максимальной производительнос ти периода выполнения. Вы можете написать и добавить в код собственную ло гику обновления за время, меньшее, чем объекту CommandBuilder потребуется, чтобы выбрать и обработать необходимые для создания аналогичного кода ме таданные. Кроме того, CommandBuilder не позволяет управлять генерацией логи ки. Нельзя указать нужный способ оптимистического управления параллелизмом.
Нельзя передавать обновления средствами хранимых процедур.
Если бы только существовал легкий и быстрый способ генерировать логику обновления в период разработки.., Создание логики обновления средствами мастера Data Adapter Configuration Wizard В главе 5 рассказывалось, как с помощью мастера Data Adapter Configuration Wizard создавать объекты DataAdapter при работе с поставщиками OLE DB и SQL Client.NET Data Provider. Кроме того, мастер генерирует логику обновления и сохраня ет се в коде.
Одно из назначений мастера Data Adapter Configuration Wizard Ч сгенериро вать в период разработки логику обновления, упростив и ускорив вам создание эффективного кода для обновления данных. Ясно, что это глобальная цель. И хотя мастер защищен от неосторожного обращения (что такое мастер?), в большин стве ситуаций он действительно создает такой код.
Откройте в Visual Studio.NET проект с элементом, предоставляющим конст руктор (например Windows-форму, Web-форму. Web-сервис или компонент), и добавьте в конструктор объект OleDbDataAdapter. Определите строку подключе ния к своей любимой БД Northwind и на вкладке SQL statement мастера введите такой запрос:
SELECT OrderlD, ProductlD, UnltPrice. Quantity FROM [Order Details] WHERE OrderlD = ? ORDER BY ProductlD Щелкните Next. Откроется окно, аналогичное показанному на рис. 10-3 Часть Ml Автономная работа с данными: объект DataSet модели ADO.NET view wizard Results Review the hit of [asks the wizard has pnforried. Click Finish to zomplete or Back to make changes.
Generated SELECT йМипиг*.
Generated tabk mssamgs, SenestKJINSEM ateinert.
Рис. 10-3. Окно View Wizard Results мастера Data Adapter Configuration Wizard Просмотр структуры объекта DataAdapter Мастер сгенерировал для нового объекта DataAdapter запросы UPDATE, INSERT и DELETE (рис. 10-3). Щелкните кнопку Finish мастера. Выберите в панели компо нентов новый объект DataAdapter. Затем в окне Properties найдите свойство Delete Command этого объекта. Выберите свойство CommandText и щелкните кнопку справа от его значения. Откроется окно Query Builder с объектом DeleteCommand (рис. 10-4).
ь OrderTO [Order Dels ProdmtlD [Order Detj -;
Cuiantltv FCIder Dets Рис. 10-4. Объект DeleteCommand, сгенерированный мастером Как видно, запрос, сгенерированный мастером Data Adapter Configuration Wizard для передачи отложенных удалений, идентичен запросу, созданному нами вруч ную в одном из предыдущих разделов главы. Кроме того, можно найти в окне Properties свойства InsertCommand и UpdateCommand объекта DataAdapter и про смотреть прочую сгенерированную мастером логику обновления.
ГЛАВА 10 Передача обновлений в базу данных Параметры генерации логики обновления В окне SQL Statement мастера есть кнопка Advanced Options, щелкнув которую вы откроете диалоговое окно, аналогичное показанному на рис. 10-5. Это окно пре доставляет ограниченные возможности управления логикой обновления, которую генерирует мастер Data Adapter Configuration Wizard.
Если ваш объект DataAdapter только выбирает данные из БД, вы сэкономите время на разработку и выполнение, сняв флажок Generate Insert, Update And Delete Statements.
По умолчанию мастер Data Adapter Configuration Wizard добавляет в раздел WHERE запросов, передающих отложенные изменения и удаления, все столбцы, не содержащие BLOB-данных. Если снять флажок Use Optimistic Concurrency, ма стер добавит в раздел WHERE таких запросов только поля первичного ключа.
Advanced SQL Generation Options Additional Insert, Update, and Delete statements can be generated Co update th* dsta uj Х V 'Generate Insert, Update and Delete statements I Generates iniert, Update, and Delete statements based on your 5e!лct statement.
'Х/ IJse optimistic concurrency Modifies Update and Delete statements to detect whether the database has changed since the record was loaded into the daEaset TNs helps prevent concurrency conflicts.
'Х> Refresh the DataSet Adds a Select statement after Insert and Update (tatements to retrieve identity column values, drfaufc values, and other values cafcuWed by the database.
Рис. 10-5. Параметры генерации логики обновления Некоторые БД, например SQL Server, поддерживают пакетные запросы, возвра щающие записи данных. Если вы с помощью мастера Data Adapter Configuration Wizard создаете объект DataAdapter, взаимодействующий с такой БД, станет дос тупным и будет помечен флажок Refresh The DataSet. При этом мастер генериру ет запросы, повторно выбирающие содержимое измененной записи сразу после передачи соответствующих изменений. Это означает, что после вызова метода DataAdapter.Update в объекте DataSet появятся новые сгенерированные сервером значения, например значения типа timestamp и значения автоинкремента.
Подробнее об этом Ч в следующей главе. Кроме того, мы рассмотрим реали зацию аналогичной функциональности для БД, которые не поддерживают пакет ные запросы, возвращающие результаты.
Передача обновлений с помощью хранимых процедур Мастер Data Adapter Configuration Wizard также позволяет создавать объекты DataAdapter, передающие изменения в БД SQL Server посредством хранимых про цедур. В окне Choose A Query Type мастера поставьте переключатель в положение Use Existing Stored Procedures (рис. 10-6) и затем щелкните Next.
Часть Ml Автономная работа с данными: объект DataSet модели ADO.NET Нои should the date.adapter access the. dal abase' '' lite SQL wernent* Spedv a Selesi лаятв* tg-lpad fffrtrnew jDrcdprocedure <' : Choose er. *risif g oied pлfOure for each opeuten (лtat. лиг!, update snd It}, Рис. 10-6. Окно Choose A Query Type мастера Data Adapter Configuration Wizard В открывшемся окне можно выбрать для всех объектов Command объекта DataAdapter хранимые процедуры. Сначала задайте значение свойства SelectCom mand. Доступные процедуры перечислены в раскрывающемся списке (рис. 10-7). При выборе процедуры в списке справа отображается возвращаемый ею столбец. SOaia ftdaplei ConllgUfalim Wizard find Commands to Existing Stored Procedures Choose tfie riotedprasziU'sscacJenLJscedVaiY'eoj'' Рис. 10-7. Задание значения свойства SelectCommand объекта DataAdapter Задав значение свойства SelectCommand, определите значения свойств Insert Command и UpdateCommand объекта DataAdapter. Чтобы задать значение свойства SourceColumn параметров ваших обновляющих хранимых процедур, воспользуй тесь списком в правой части окна мастера (рис. 10-8). Примечание Мастер Data Adapter Configuration Wizard не позволяет задавать значение свойства SourceVersion объектов Parameter. Поскольку по умол чанию оно равно Current, вам следует с помощью окна Properties изме нить его для всех параметров, которые вы хотите связать с оригиналь ным значением измененных столбцов. ГЛАВА 10 Передача обновлений в базу данных Bind Commands to Existing Stared Procedures a scored рюевАяв far each и*гл*сл. If Ич arocedu hfch tmif* Нч data row nrtains the рагвгийг Set Irtr( oraeedur; parameters I Pe-amл*f Source Cofcjrm jeOraerl!} СтдвгШ i^Produd^D ProdutilC i@Quanl4r Quanttv jiJUntPrite Lntf-bie Рис. 10-8. Значения свойства SourceColumn параметров объекта InsertCommand Если у вас установлена Visual Studio.NET Enterprise Edition, можно также ука зать SQL-запрос, и мастер Data Adapter Configuration Wizard сгенерирует новые хранимые процедуры SQL Server для свойств SelectCommand. UpdateCommand, InsertCommand и DeleteCommand вашего объекта DataAdapter. В окне Choose A Query Туре мастера поставьте переключатель в положение Create New Stored Procedures; мастер предложит вам ввести SQL-запрос, возвращающий данные из БД (рис. 10-9). atB Aiplpr Canfieurniion УНгатй Generate the stored procedures The Stlлt stemeni Mil bg used to male th Meet. Зкеге, Update id Mete stored t*xedures. Tycein vour a^3etelstetлTient-B1^ttw>jefy Mder to^ep^all/ hit dtBihouU)lh= data adapter toad info the dalasrt? 5ELECI --. ?roductlDp ftdwnted Opt Рис. 10-9- Ввод SQL-запроса для новых хранимых процедур В следующем окне можно ввести имена генерируемых мастером хранимых процедур. Кроме того, здесь имеется кнопка Preview SQL Script, при щелчке кото рой открывается диалоговое окно с SQL-сценарием, который мастер Data Adapter Configuration Wizard сгенерировал для создания ваших хранимых процедур (рис 10-10). Если вы создаете приложение для работы с тестовой БД, воспользуйтесь этим диалоговым окном и сохраните SQL-сценарий в файл, чтобы позже выпол нять его в рабочей БД. Автономная работа с данными: объект DataSet модели ЛЕЮ.NET 382 Часть III SET МОССЛЛГ W; SELECT OKierta o-MucllO ?.-*Ч-:-. Unltfritt FfiOMfOrder Details] WHERE - (OtdsHD - ЮО-Я-Ю) O4XR BV =-(rfucSP; IM5EBT INTO[OrdH E><*] (OntotlD, Р ЗИ.ЕСТ DriterlO, ProdutllD, IjHrHh', LN(P" FRCrt J5rdw W*^ MtRE (OrdwlD. pOrdjrlC) *NO (Produc:ID - JProBultES OCS! ВУ ProdutllP; S^ve As,. ; ppy** Рис. 10-10. Просмотр SQL-сценария, сгенерированного мастером для создания новых хранимых процедур По завершении работы с мастером в БД появятся новые хранимые процедуры и объект DataAdapter будет сконфигурирован для работы с ними. Преимущества и недостатки использования мастера Как уже говорилось, одно из назначений мастера Data Adapter Configuration Wizard Ч сгенерировать логику обновления, упростив и ускорив вам создание эф фективного кода для обновления данных. Мастер предоставляет больше возмож ностей, чем объект CommandBuilder. Кроме того, он генерирует скучный код, ко торый многие разработчики предпочитают не писать. И хотя для создания логики обновления мастер запрашивает из БД ту же ин формацию схемы, что и объект CommandBuilder, он делает это лишь единожды, в период разработки, и затем сохраняет сгенерированную логику в коде. Таким образом, производительность приложения в период выполнения не падает, в от личие от использования объекта CommandBuilder. Но увы, мастер Data Adapter Configuration Wizard несовершенен. В первой версии Visual Studio.NET он работает только с объектами DataAdapter поставщиков OLE DB и SQL Client.NET Data Provider. Кроме того, он предоставляет ограниченные возможности контроля параллелизма. Изменять объекты Command, генерируемые мастером, можно, но при изменении конфигурации объекта DataAdapter все эти изменения будут утеряны. И все же, несмотря на свое несовершенство, мастер Data Adapter Configuration Wizard Ч мощная и полезная утилита. Прочие проблемы обновления Вы уже изучили основные принципы обновления содержимого БД с использова нием отложенных изменений, хранящихся в объекте DataSet. Если вы генерируе те собственную логику1 обновления (в форме запросов INSERT, UPDATE и DELETE или вызовов хранимых процедур), вам необходимо знать больше, чем просто основы. ГЛАВА 10 Передача обновлений в базу данных Например, как управлять параллелизмом, чтобы случайно не перезаписать изменения, сделанные другим пользователем? Как обрабатывать значения NULL при управлении параллелизмом? Как передавать обновления в транзакции? Какую роль играет набор TableMappings объекта DataAdapter при передаче обновлений? Подробнее о том, как осуществить это Ч в последующих разделах, Способы оптимистичного управления параллелизмом При создании многопользовательского приложения для работы с БД. передающего обновления с применением оптимистичного управления параллелизмом, важно реализовать в обновляющих запросах оптимистичный контроль параллелизма. Скажем, два пользователя вашего приложение запросили одну и ту же запись дан
The server is temporarily unable to service your
request due to maintenance downtime or capacity
problems. Please try again later.Service Unavailable
