ADO.NET, l'utilizzo pratico nelle applicazioni Silvano Coriani Developer & Platform Evangelism MCTrainer MCSDeveloper MCADeveloper MCSEInternet MCDBA 1 / 31 Da dove iniziare... 2 / 31 Agenda 3 / 31 Popolare il DataSet • MissingSchemaAction 4 / 31 Popolare il DataSet • unicounaunicotutte 5 / 31 Popolare il DataSet 6 / 31 Popolare il DataSet • ExecuteXmlReader() 7 / 31 Popolare il DataSet 8 / 31 Popolare il DataSet 9 / 31 Semplici aggiornamenti in ADO.NET • DataAdapter [C#] SqlDataAdapter custDA = new SqlDataAdapter("SELECT * FROM Customers",nwindConn); SqlCommandBuilder custCB = new SqlCommandBuilder(custDA); nwindConn.Open(); DataSet custDS = new DataSet(); custDA.Fill(custDS, "Customers"); // Modifico il dataset // Senza il SqlCommandBuilder l’Update fallirebbe custDA.Update(custDS, "Customers"); nwindConn.Close(); 10 / 31 Semplici aggiornamenti in ADO.NET • valori originaliCommandBuilder li ricava dal comando di Select • Noi conosciamo la logica di aggiornamento dei dati meglio del CommandBuilder • Costruiamoli da codice o facciamoli costruire da VS.NET 11 / 31 Come funziona il metodo Update? CustomerDataTable Select Insert DB Customers Update Delete 12 / 31 Creazione manuale dei comandi del DataAdapter • RowVersion 13 / 31 Comando di Update del DataAdapter string strSQL = "SELECT CustomerID, CompanyName FROM Customers“; SqlConnection cnn = new SqlConnection(“Server=(local);...“); SqlDataAdapter = new SqlDataAdapter(str,cnn); string strSQLUpd = "UPDATE Customers SET CustomerID = ?, CompanyName = ? WHERE CustomerID = ? AND CompanyName = ?“; da.UpdateCommand = new SqlCommand(strSQLUpd, cnn) da.UpdateCommand.Parameters.Add(new SqlParameter("NewCustomerID", SqlDbType.WChar, 5,ParameterDirection.Input, false, 0, 0, "CustomerID", DataRowVersion.Current, null)); da.UpdateCommand.Parameters.Add(new SqlParameter("NewCompanyName", SqlDbType.VarWChar, 40, ParameterDirection.Input, false, 0, 0, "CompanyName", DataRowVersion.Current, null)); da.UpdateCommand.Parameters.Add(new SqlParameter("OldCustomerID", SqlDbType.WChar, 5, ParameterDirection.Input, false, 0, 0, "CustomerID", DataRowVersion.Original, null)); da.UpdateCommand.Parameters.Add(new SqlParameter("OldCompanyName", SqlDbType.VarWChar, 40, ParameterDirection.Input, false, 0, 0, "CompanyName", DataRowVersion.Original, null)); 14 / 31 [SQL Code] CREATE PROCEDURE UpdateCustomer (@NewCustomerID nchar(5), @NewCompanyName nvarchar(40), @OldCustomerID nchar(5), @OldCompanyName nvarchar(40)) AS UPDATE Customers SET CustomerID = @NewCustomerID, CompanyName = @NewCompanyName WHERE CustomerID = @OldCustomerID AND CompanyName = @OldCompanyName [ADO.NET Code] da.UpdateCommand.CommandText = "UpdateCustomer“; da.UpdateCommand.CommandType = CommandType.StoredProcedure; da.UpdateCommand.Parameters.Add(new SqlParameter("NewCustomerID", SqlDbType.WChar, 5,ParameterDirection.Input, false, 0, 0, "CustomerID", DataRowVersion.Current, null)); da.UpdateCommand.Parameters.Add(new SqlParameter("NewCompanyName", SqlDbType.VarWChar, 40, ParameterDirection.Input, false, 0, 0, "CompanyName", DataRowVersion.Current, null)); da.UpdateCommand.Parameters.Add(new SqlParameter("OldCustomerID", SqlDbType.WChar, 5, ParameterDirection.Input, false, 0, 0, "CustomerID", DataRowVersion.Original, null)); da.UpdateCommand.Parameters.Add(new SqlParameter("OldCompanyName", SqlDbType.VarWChar, 40, ParameterDirection.Input, false, 0, 0, "CompanyName", DataRowVersion.Original, null)); 15 / 31 Aggiornamenti sull’oggetto DataTable • Per inserire un record sull’oggetto DataTable – AddRow()Detached – Rows.Add(DataRow)Added – AcceptChanges() esegue la commit di tutte le modifiche nella cache locale. Riporta a UnChanged le righe inserite e modificate. Rimuove le eliminate. – RejectChanges() 16 / 31 Aggiornamenti sulla DataTable • Current • HasVersion()RowUpdated 17 / 31 Aggiornamenti sulla DataTable • RowState – RowErrorHasErrorstrue 18 / 31 Aggiornamenti sulla DataTable • Select()DataRows – DataViewRowState 19 / 31 Merge di DataSet • stato 20 / 31 Gestione dei conflitti 21 / 31 Gestione della concorrenza con ADO.NET • Timestamp 22 / 31 Transazioni in ADO.NET • Transazioni distribuite – Utilizzando gli EnterpriseServices di .NET o COM+ – La connessione al singolo DB viene arruolata dal MS DTC all’interno del contesto di una transazione – Utilizza two-phase commit su Ole Transaction o XA per i vari Resource Manager – Da usare solo quando veramente necessario • Transazioni locali – All’interno del codice SQL delle Stored Procedure • BEGIN/COMMIT TRAN – SqlTransaction 23 / 31 Transazioni in ADO.NET [C#] SqlConnection conn = new SqlConnection(); conn.Open("..."); SqlTransaction tx = conn.BeginTransaction(); SqlCommand cmd = conn.CreateCommand(); cmd.CommandText = "..."; cmd.Transaction = tx; cmd.ExecuteNonQuery(); tx.Commit(); 24 / 31 Concorrenza ottimistica in SQL Server • ts_equal() 25 / 31 Concorrenza ottimistica in ADO.NET • Update()DBConcurrencyExceptionContinueUpdat eOnErrorHasError 26 / 31 Concorrenza ottimistica in ADO.NET • RowUpdated [C#] daMain.RowUpdated += new SqllRowUpdatedEventHandler(HandleRowUpdated); … private void HandleRowUpdated(object sender, SqlRowUpdatedEventArgs e) { if ((e.Status == UpdateStatus.ErrorsOccurred) && (e.Errors.GetType == typeof(DBConcurrencyException)) { daConflict.SelectCommand.Parameters[0].Value = e.Row["ID"]; int intRowsReturned = ConflictAdapter.Fill(ConflictDataSet); if (intRowsReturned == 1) e.Row.RowError =“The row has been modified by another user."; else e.Row.RowError = "The row no longer exists in the database."; e.Status = UpdateStatus.Continue;// determina se proseguire o no } } 27 / 31 Re-fetching di una riga dopo l’update • UpdateRowSource INSERT INTO Orders (CustomerID, EmployeeID, OrderDate) VALUES (?, ?, GetDate()); SELECT OrderID, CustomerID, EmployeeID, OrderDate FROM Orders WHERE OrderID = @@IDENTITY 28 / 31 Aggiornamento di dati gerarchici • Select()DataRowState.AddedDataRowState.Delet ed 29 / 31 Lavorare con i campi di tipo IDENTITY • AutoIncrementSeedAutoIncrementStepDataTable Select()DataRowUpdate() 30 / 31 Link utili 31 / 31 News 32 / 31 33 / 31