用SqlDataAdapter.Update(DataSet Ds)更新数据库
一. 用SqlDataAdapter.Update(DataSet Ds)更新數據庫.
1. DbDataAdapter調用 Update 方法時,DataAdapter 將分析已作出的更改并執行相應的命令(INSERT、UPDATE 或 DELETE)。當 DataAdapter 遇到對 DataRow 的更改時,它將使用 InsertCommand、UpdateCommand 或 DeleteCommand 來處理該更改。這樣,您就可以通過在設計時指定命令語法并在可能時通過使用存儲過程來盡量提高 ADO.NET 應用程序的性能。在調用 Update 之前,必須顯式設置這些命令。如果調用了 Update 但不存在用于特定更新的相應命令(例如,不存在用于已刪除行的 DeleteCommand),則將引發異常。
但是如果 DataTable 映射到單個數據庫表或從單個數據庫表生成,則可以利用 CommandBuilder 對象自動生成 DataAdapter 的 DeleteCommand、InsertCommand 和 UpdateCommand。為了自動生成命令,必須設置 SelectCommand 屬性,這是最低的要求。SelectCommand 所檢索的表架構 確定自動生成的 INSERT、UPDATE 和 DELETE 語句的語法。如果在自動生成插入、更新或刪除命令后修改 SelectCommand 的 CommandText,則可能會發生異常。如果已修改的 SelectCommand.CommandText 所包含的架構信息與自動生成插入、更新或刪除命令時所使用的 SelectCommand.CommandText 不一致,則以后對 DataAdapter.Update 方法的調用可能會試圖訪問 SelectCommand 引用的當前表中已不存在的列,并且會引發異常。可以通過調用 CommandBuilder 的 RefreshSchema 方法來刷新 CommandBuilder 用來自動生成命令的架構信息。
對于DbDataAdapter.Update 方法更新數據庫,每次在調用DbDataAdapter.Update(ds) 之后一定要ds.acceptchanges
否則會對后面用到的ds出現意想不到的錯誤。
郁悶~ 改了一天的程序,才發現是這個錯誤,太郁悶了~~
2. SqlCommandBuilder會自動生成更新、修改、刪除的sql語句,進行更新。
3.當表中沒有主鍵時,自動生成的SQL語句進行UPDate時,會出現異常信息。
異常信息為:用SqlCommandBuilder更新DataSet,遇到“對于不返回任何鍵列信息的 SelectCommand 不支持 UpdateCommand 的動態 SQL 生成”問題。
4.解決辦法:1. 修改表的定義,定義一個主鍵;
2. 為SqlDataAdapter指定UpdateCommand(DeleteCommand,InsertCommand應該也一樣);
例子:
1.string emailSql="select email,validFlag from emailMe";
DataSet emailAdd=new DataSet();
SqlDataAdapter emailAdapter=new SqlDataAdapter(emailSql,myConn);
SqlCommandBuilder cb=new SqlCommandBuilder(emailAdapter);
emailAdapter.Fill(emailAdd,"address");
myConn.Close();
DataTable myDt=emailAdd.Tables["address"];
myDt.PrimaryKey=new DataColumn[]{myDt.Columns["email"]};
......//修改myDs數據
emailAdapter.Update(emailAdd,"address");
自動生成SQL語句。
2. string emailSql="select email,validFlag from emailMe";
DataSet emailAdd=new DataSet();
SqlDataAdapter emailAdapter=new SqlDataAdapter(emailSql,myConn);
SqlCommandBuilder cb=new SqlCommandBuilder(emailAdapter);
SqlCommand upCmd=new SqlCommand("update ["+strTableName+"] set validFlag=@validFlag where email=@email",myConn);
upCmd.Parameters.Add("@validFlag",SqlDbType.Int,8,"validFlag");
upCmd.Parameters.Add("@email",SqlDbType.NVarChar,100,"email");
emailAdapter.UpdateCommand=upCmd;
emailAdapter.Fill(emailAdd,"address");
myConn.Close();
......//修改myDs數據
emailAdapter.Update(emailAdd,"address");
自定義SQL語句。
二.檢索“標識”或“自動編號”值
檢索“標識”或“自動編號”值
此頁面僅適用于
Microsoft Visual Studio 2005/.NET Framework 2.0
同時提供下列產品的其他版本:
Microsoft Visual Studio 2008/.NET Framework 3.5
.NET Framework 開發人員指南
檢索“標識”或“自動編號”值
為了確保表中的每一行都有唯一的值,可以將 DataTable 中的列設置為自動遞增的主鍵。但是,您的應用程序可能會有多個客戶端,而每個客戶端都可能會使用一個單獨的 DataTable 實例。在這種情況下,單獨的 DataTable 實例之間最終可能會出現重復的值。由于所有客戶端都使用單個數據源,因此可以讓數據源定義自動遞增值,從而解決這一沖突。若要完成此任務,請使用 Microsoft SQL Server 中的“標識”列或 Microsoft Access 中的“自動編號”字段。
如果使用數據源為添加到 DataSet 中的新行填充“標識”或“自動編號”列,則會出現唯一的情況,因為 DataSet 與數據源之間沒有直接連接。因此,DataSet 不識別任何由數據源自動生成的值。但是,對于可以創建帶有輸出參數的存儲過程的數據源(如 Microsoft SQL Server),可以將自動生成的值(如新的標識值)指定為輸出參數并使用 DataAdapter 將該值映射回 DataSet 中的相應列。
數據源可能不支持帶有輸出參數的存儲過程。在這種情況下,將可以使用 RowUpdated 事件來檢索自動生成的值,并將其放入 DataSet 中的插入行或更新行。本節包含一個示例,顯示當在 Microsoft Access 2000 或更高版本上使用 Jet 4.0 OLE DB 提供程序時,如何將代碼添加到 RowUpdated 事件中以確定插入是否已發生,然后檢索自動生成的值并將其存儲在當前更新的行中。
檢索 SQL Server“標識”列的值
以下存儲過程和代碼示例顯示如何將自動遞增的標識值從 Microsoft SQL Server 表映射回添加到向 DataSet 的表添加的行中的相應列。該存儲過程用于將一個新行插入 Northwind 數據庫的 Categories 表并以輸出參數的形式返回從 Transact-SQL SCOPE_IDENTITY() 函數返回的標識值。
復制代碼
CREATE PROCEDURE InsertCategory
@CategoryName nchar(15),
@Identity int OUT
AS
INSERT INTO Categories (CategoryName) VALUES(@CategoryName)
SET @Identity = SCOPE_IDENTITY()
InsertCategory 存儲過程可以指定為 InsertCommand 的源。為接收“標識”輸出參數創建一個參數。該參數具有 Output 的 ParameterDirection,并將 SourceColumn 指定為 DataSet 中本地 Categories 表的 CategoryID 列。為添加的行處理 InsertCommand 后,將自動遞增的標識值作為此輸出參數返回,然后放入當前行的 CategoryID 列中。
以下代碼示例顯示如何以輸出參數的形式返回自動遞增的值并將其指定為 DataSet 中 CategoryID 列的源值。
Visual Basic
復制代碼
' Assumes that connection is a valid SqlConnection object.
Dim adapter As SqlDataAdapter = New SqlDataAdapter( _
"SELECT CategoryID, CategoryName FROM dbo.Categories", connection)
adapter.InsertCommand = New SqlCommand("InsertCategory", connection)
adapter.InsertCommand.CommandType = CommandType.StoredProcedure
adapter.InsertCommand.Parameters.Add( _
"@CategoryName", SqlDbType.NChar, 15, "CategoryName")
Dim parameter As SqlParameter = adapter.InsertCommand.Parameters.Add( _
"@Identity", SqlDbType.Int, 0, "CategoryID")
parameter.Direction = ParameterDirection.Output
connection.Open()
Dim categories As DataSet = New DataSet
adapter.Fill(categories, "Categories")
Dim newRow As DataRow = categories.Tables("Categories").NewRow()
newRow("CategoryName") = "New Category"
categories.Tables("Categories").Rows.Add(newRow)
adapter.Update(categories, "Categories")
connection.Close()
C#
復制代碼
// Assumes that connection is a valid SqlConnection object.
SqlDataAdapter adapter = new SqlDataAdapter(
"SELECT CategoryID, CategoryName FROM dbo.Categories", connection);
adapter.InsertCommand = new SqlCommand("InsertCategory", connection);
adapter.InsertCommand.CommandType = CommandType.StoredProcedure;
adapter.InsertCommand.Parameters.Add(
"@CategoryName", SqlDbType.NChar, 15, "CategoryName");
SqlParameter parameter = adapter.InsertCommand.Parameters.Add(
"@Identity", SqlDbType.Int, 0, "CategoryID");
parameter.Direction = ParameterDirection.Output;
connection.Open();
DataSet categories = new DataSet();
adapter.Fill(categories, "Categories");
DataRow newRow = categories.Tables["Categories"].NewRow();
newRow["CategoryName"] = "New Category";
categories.Tables["Categories"].Rows.Add(newRow);
adapter.Update(categories, "Categories");
connection.Close();
檢索 Microsoft Access“自動編號”值
Microsoft Access 不支持存儲過程或批命令處理,因此無法將輸出參數映射到上例所示表中的源列。但是,Microsoft Access 2000 或更高版本支持 @@IDENTITY 屬性在“插入”(INSERT) 后檢索“自動編號”字段的值。使用 RowUpdated 事件,您可以確定“插入”(INSERT) 是否已發生,檢索最新的“自動編號”值,然后將該值放入 DataSet 中本地表的“標識”列。
以下代碼示例顯示如何使用 OleDbDataAdapter 將一個新值插入 Microsoft Access 2000 Northwind 數據庫的 Categories 表中。該示例使用 RowUpdated 事件來填充在向 Categories 表中插入記錄時 Jet 引擎和 Access 數據庫所生成的“自動編號”值。請注意,這僅適用于 Jet 4.0 OLE DB 提供程序和 Microsoft Access 2000 或更高版本。
Visual Basic
復制代碼
' Assumes that connection is a valid OleDbConnection object.
' Use the DataAdapter to fill and update the DataSet.
Dim adapter As OleDbDataAdapter = New OleDbDataAdapter( _
"SELECT CategoryID, CategoryName FROM Categories ORDER BY CategoryID", _
connection)
adapter.InsertCommand = New OleDbCommand( _
"INSERT INTO Categories (CategoryName) Values(?)", connection)
adapter.InsertCommand.CommandType = CommandType.Text
adapter.InsertCommand.Parameters.Add( _
"@CategoryName", OleDbType.Char, 15, "CategoryName")
connection.Open()
' Fill the DataSet.
Dim categories As DataSet = New DataSet
adapter.Fill(categories, "Categories")
' Add a new row.
Dim newRow As DataRow = categories.Tables("Categories").NewRow()
newRow("CategoryName") = "New Category"
categories.Tables("Categories").Rows.Add(newRow)
' Include an event to fill in the Autonumber value.
AddHandler adapter.RowUpdated, _
New OleDbRowUpdatedEventHandler(AddressOf OnRowUpdated)
' Update the DataSet.
adapter.Update(categories, "Categories")
connection.Close()
' Event procedure for OnRowUpdated
Private Shared Sub OnRowUpdated( _
sender As Object, args As OleDbRowUpdatedEventArgs)
' Include a variable and a command to retrieve the identity value
' from the Access database.
Dim newID As Integer = 0
Dim idCMD As OleDbCommand = New OleDbCommand( _
"SELECT @@IDENTITY", connection)
If args.StatementType = StatementType.Insert
' Retrieve the identity value and store it in the CategoryID column.
newID = CInt(idCMD.ExecuteScalar())
args.Row("CategoryID") = newID
End If
End Sub
C#
復制代碼
// Assumes that connection is a valid OleDbConnection object.
OleDbDataAdapter adapter = new OleDbDataAdapter(
"SELECT CategoryID, CategoryName FROM Categories ORDER BY CategoryID",
connection);
adapter.InsertCommand = new OleDbCommand(
"INSERT INTO Categories (CategoryName) Values(?)", connection);
adapter.InsertCommand.CommandType = CommandType.Text;
adapter.InsertCommand.Parameters.Add( _
"@CategoryName", OleDbType.Char, 15, "CategoryName");
connection.Open();
// Fill the DataSet.
DataSet categories = new DataSet();
adapter.Fill(categories, "Categories");
// Add a new row.
DataRow newRow = categories.Tables["Categories"].NewRow();
newRow["CategoryName"] = "New Category";
categories.Tables["Categories"].Rows.Add(newRow);
// Include an event to fill in the Autonumber value.
adapter.RowUpdated += new OleDbRowUpdatedEventHandler(OnRowUpdated);
// Update the DataSet.
adapter.Update(categories, "Categories");
connection.Close();
// Event procedure for OnRowUpdated
protected static void OnRowUpdated(
object sender, OleDbRowUpdatedEventArgs args)
{
// Include a variable and a command to retrieve the identity value from the Access database.
int newID = 0;
OleDbCommand idCMD = new OleDbCommand(
"SELECT @@IDENTITY", connection);
if (args.StatementType == StatementType.Insert)
{
// Retrieve the identity value and store it in the CategoryID column.
newID = (int)idCMD.ExecuteScalar();
args.Row["CategoryID"] = newID;
}
三.使用 DataAdapter 和 DataSet 更新數據庫 [C#]
DataAdapter 的 Update 方法可調用來將 DataSet 中的更改解析回數據源。與 Fill 方法類似,Update 方法將 DataSet 的實例和可選的 DataTable 對象或 DataTable 名稱用作參數。DataSet 實例是包含已作出的更改的 DataSet,而 DataTable 標識從其中檢索更改的表。
當調用 Update 方法時,DataAdapter 將分析已作出的更改并執行相應的命令(INSERT、UPDATE 或 DELETE)。當 DataAdapter 遇到對 DataRow 的更改時,它將使用 InsertCommand、UpdateCommand 或 DeleteCommand 來處理該更改。這樣,您就可以通過在設計時指定命令語法并在可能時通過使用存儲過程來盡量提高 ADO.NET 應用程序的性能。在調用 Update 之前,必須顯式設置這些命令。如果調用了 Update 但不存在用于特定更新的相應命令(例如,不存在用于已刪除行的 DeleteCommand),則將引發異常。
Command 參數可用于為 DataSet 中每個已修改行的 SQL 語句或存儲過程指定輸入和輸出值。有關更多信息,請參閱將參數用于 DataAdapter。
如果 DataTable 映射到單個數據庫表或從單個數據庫表生成,則可以利用 CommandBuilder 對象自動生成 DataAdapter 的 DeleteCommand、InsertCommand 和 UpdateCommand。有關更多信息,請參閱自動生成的命令。
Update 方法會將更改解析回數據源,但是自上次填充 DataSet 以來,其他客戶端可能已修改了數據源中的數據。若要使用當前數據刷新 DataSet,請再次使用 DataAdapter 填充 (Fill) DataSet。新行將添加到該表中,更新的信息將并入現有行。
若要處理可能在 Update 操作過程中發生的異常,可以使用 RowUpdated 事件在這些異常發生時響應行更新錯誤(請參閱使用 DataAdapter 事件),或者可以在調用 Update 之前將 DataAdapter.ContinueUpdateOnError 設置為 true,然后在 Update 完成時響應存儲在特定行的 RowError 屬性中的錯誤信息(請參閱添加和讀取行錯誤信息)。
注意 如果對 DataSet、DataTable 或 DataRow 調用 AcceptChanges,則將使某 DataRow 的所有 Original 值被該 DataRow 的 Current 值改寫。如果已修改將該行標識為唯一行的字段值,那么當調用 AcceptChanges 后,Original 值將不再匹配數據源中的值。
以下示例演示如何通過顯式設置 DataAdapter 的 UpdateCommand 來執行對已修改行的更新。請注意,在 UPDATE 語句的 WHERE 子句中指定的參數設置為使用 SourceColumn 的 Original 值。這一點很重要,因為 Current 值可能已被修改,并且可能不匹配數據源中的值。Original 值是曾用來從數據源填充 DataTable 的值。
SqlClient
[Visual Basic]
Dim catDA As SqlDataAdapter = New SqlDataAdapter("SELECT CategoryID, CategoryName FROM Categories", nwindConn)
catDA.UpdateCommand = New SqlCommand("UPDATE Categories SET CategoryName = @CategoryName " & _
"WHERE CategoryID = @CategoryID", nwindConn)
catDA.UpdateCommand.Parameters.Add("@CategoryName", SqlDbType.NVarChar, 15, "CategoryName")
Dim workParm As SqlParameter = catDA.UpdateCommand.Parameters.Add("@CategoryID", SqlDbType.Int)
workParm.SourceColumn = "CategoryID"
workParm.SourceVersion = DataRowVersion.Original
Dim catDS As DataSet = New DataSet
catDA.Fill(catDS, "Categories")
Dim cRow As DataRow = catDS.Tables("Categories").Rows(0)
cRow("CategoryName") = "New Category"
catDA.Update(catDS)
[C#]
SqlDataAdapter catDA = new SqlDataAdapter("SELECT CategoryID, CategoryName FROM Categories", nwindConn);
catDA.UpdateCommand = new SqlCommand("UPDATE Categories SET CategoryName = @CategoryName " +
"WHERE CategoryID = @CategoryID" , nwindConn);
catDA.UpdateCommand.Parameters.Add("@CategoryName", SqlDbType.NVarChar, 15, "CategoryName");
SqlParameter workParm = catDA.UpdateCommand.Parameters.Add("@CategoryID", SqlDbType.Int);
workParm.SourceColumn = "CategoryID";
workParm.SourceVersion = DataRowVersion.Original;
DataSet catDS = new DataSet();
catDA.Fill(catDS, "Categories");
DataRow cRow = catDS.Tables["Categories"].Rows[0];
cRow["CategoryName"] = "New Category";
catDA.Update(catDS);
OleDb
[Visual Basic]
Dim catDA As OleDbDataAdapter = New OleDbDataAdapter("SELECT CategoryID, CategoryName FROM Categories", nwindConn)
catDA.UpdateCommand = New OleDbCommand("UPDATE Categories SET CategoryName = ? " & _
"WHERE CategoryID = ?" , nwindConn)
catDA.UpdateCommand.Parameters.Add("@CategoryName", OleDbType.VarChar, 15, "CategoryName")
Dim workParm As OleDbParameter = catDA.UpdateCommand.Parameters.Add("@CategoryID", OleDbType.Integer)
workParm.SourceColumn = "CategoryID"
workParm.SourceVersion = DataRowVersion.Original
Dim catDS As DataSet = New DataSet
catDA.Fill(catDS, "Categories")
Dim cRow As DataRow = catDS.Tables("Categories").Rows(0)
cRow("CategoryName") = "New Category"
catDA.Update(catDS)
[C#]
OleDbDataAdapter catDA = new OleDbDataAdapter("SELECT CategoryID, CategoryName FROM Categories", nwindConn);
catDA.UpdateCommand = new OleDbCommand("UPDATE Categories SET CategoryName = ? " +
"WHERE CategoryID = ?" , nwindConn);
catDA.UpdateCommand.Parameters.Add("@CategoryName", OleDbType.VarChar, 15, "CategoryName");
OleDbParameter workParm = catDA.UpdateCommand.Parameters.Add("@CategoryID", OleDbType.Integer);
workParm.SourceColumn = "CategoryID";
workParm.SourceVersion = DataRowVersion.Original;
DataSet catDS = new DataSet();
catDA.Fill(catDS, "Categories");
DataRow cRow = catDS.Tables["Categories"].Rows[0];
cRow["CategoryName"] = "New Category";
catDA.Update(catDS);
自動遞增列
如果來自數據源的表包含自動遞增列,則可以使用由數據源生成的值填充 DataSet 中的列,方法是通過以存儲過程輸出參數的形式返回自動遞增值并將其映射到表中的一列,或者使用 DataAdapter 的 RowUpdated 事件。有關示例,請參閱檢索“標識”或“自動編號”值。
但是,DataSet 中的值可能會與數據源中的值不同步并導致意外的行為。例如,請考慮一個包含自動遞增主鍵列 CustomerID 的表。如果在該 DataSet 中添加兩個新客戶,它們將收到自動遞增的 CustomerId 值 1 和 2。在向 DataAdapter 的 Update 方法傳遞第二個客戶行時,新添加的行會收到數據源中的自動遞增 CustomerID 值 1,該值與 DataSet 中的值 2 不匹配。當 DataAdapter 使用返回值填充 DataSet 中的行時,由于第一個客戶行的 CustomerID 已經是 1,因此將發生約束沖突。
為了避免這種行為,建議在使用數據源中的自動遞增列和 DataSet 中的自動遞增列時,在 DataSet 中創建 AutoIncrementStep 為 -1 且 AutoIncrementSeed 為 0 的列,并確保數據源生成從 1 開始并以正步長值遞增的自動遞增標識值。這樣,DataSet 將為自動遞增值生成負數,這些負數不會與數據源所生成的正自動遞增值發生沖突。另一種方法是使用 Guid 類型的列而不是自動遞增列。生成 Guid 值的算法在 DataSet 中生成的 Guid 從不會與數據源生成的 Guid 相同。有關定義 DataTable 中的列的更多信息,請參閱定義數據表的架構。
插入、更新和刪除的排序
在許多情況下,以何種順序向數據源發送通過 DataSet 作出的更改是相當重要的。例如,如果已更新現有行的主鍵值并且添加了具有新主鍵值的新行,則務必要在處理插入之前處理更新。
可以使用 DataTable 的 Select 方法來返回僅引用具有特定 RowState 的 DataRow 數組。然后可以將返回的 DataRow 數組傳遞到 DataAdapter 的 Update 方法來處理已修改的行。通過指定要更新的行的子集,可以控制處理插入、更新和刪除的順序。
轉載于:https://www.cnblogs.com/top5/archive/2010/03/24/1693770.html
總結
以上是生活随笔為你收集整理的用SqlDataAdapter.Update(DataSet Ds)更新数据库的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 云朵机(人造云朵,造云机)用在互动百科推
- 下一篇: 和 Gmail 先生面对面