Download presentation
Presentation is loading. Please wait.
Published byNorah Copeland Modified over 9 years ago
1
DAT402 Microsoft ® ADO.NET: Blackbelt DAT402 Microsoft ® ADO.NET: Blackbelt Gert E.R. Drapers Architect Microsoft Corp.
2
Agenda Common Techniques Common Techniques Optimizing Performance Optimizing Performance Security Considerations Security Considerations Questions Questions
3
Agenda Common Techniques Common Techniques – Updating from a DataSet – Server Cursors and ADO.NET – Using the DataSet as a Cache – Controlling how XML is generated – Working with Identity Columns – Handling Large ResultSets – Join Queries against a DataSet – Recordset Dataset Optimizing Performance Optimizing Performance Security Considerations Security Considerations
4
Updating From A DataSet Use a DataAdapter Use a DataAdapter – Typically one per table to be updated – Specify Insert, Update, Delete commands Use CommandBuilder for AdHoc queries Use CommandBuilder for AdHoc queries – Designers, tools – Call Update(), passing in DataSet/DataTable to be updated No persistent connection between DataAdapter and DataSet No persistent connection between DataAdapter and DataSet – Can use different DataAdapters for Fill and Update – Use ExtendedProperties to pass datasource information
5
Specifying Update Commands Associate parameters with DataSet Columns Associate parameters with DataSet Columns – Specify SourceColumn property – Parameter values will be set using values from the Dataset for each Insert, Update, or Delete 'Specify Delete Command Dim delete As New SqlCommand("DeleteOrder", cnn) delete.CommandType = CommandType.StoredProcedure 'Create a Parameter and associate it with Dataset column Dim param As New SqlParameter("@OrderID", SqlDbType.Int) param.SourceColumn = "OrderID" delete.Parameters.Add(param) 'Set as the Delete Command adapter.DeleteCommand = delete
6
Dim adapter As New SqlDataAdapter() Dim delete As New SqlCommand("DeleteOrder", cnn) delete.CommandType = CommandType.StoredProcedure delete.Parameters.Add("@OrderID", SqlDbType.Int).SourceColumn = "OrderID" adapter.DeleteCommand = delete Dim insert As New SqlCommand("AddOrder", cnn) insert.CommandType = CommandType.StoredProcedure insert.Parameters.Add("@OrderID", SqlDbType.Int).SourceColumn = "OrderID" insert.Parameters.Add("@CustD", SqlDbType.Int).SourceColumn = "CustomerID" insert.Parameters.Add("@Date", SqlDbType.DateTime).Value = DateTime.Now adapter.InsertCommand = insert Dim update As New SqlCommand("UpdateOrder", cnn) update.CommandType = CommandType.StoredProcedure update.Parameters.Add("@OrderID",SqlDbType.Int).SourceColumn="Or derID" update.Parameters.Add("@CustD",SqlDbType.Int).SourceColumn="Cust omerID" adapter.UpdateCommand = update adapter.Update(ordersTable) Updating Example
7
Optimistic Concurrency Specify Original values or RowVersion column Specify Original values or RowVersion column – Original values for changes made to data read – RowVersion for any changes made to row Set SourceVersion for original values Set SourceVersion for original values Account for Nulls in Where clause: Account for Nulls in Where clause: Add additional logic in Stored Procedure for handling concurrency and conflicts Add additional logic in Stored Procedure for handling concurrency and conflicts WHERE ((Country ISNULL) AND (@Country ISNULL)) OR (Country=@Country) Dim update As New SqlCommand("Update Customers (Name) Values " & _ "(@Name) Where Name=@OldName AND CustID=@ID",cnn) update.Parameters.Add("@Name",SqlDbType.VarChar).SourceColumn = "Name" update.Parameters.Add("@CustID",SqlDbType.Int).SourceColumn = "CustomerID" Dim param = update.Parameters.Add("@OldName",SqlDbType.VarChar) param.SourceColumn = "Name" param.SourceVersion = DataRowVersion.Original
8
Server Cursors And ADO.NET DataReader versus DataSet DataReader versus DataSet – DataReader is a Forward Only/Read Only "Server Cursor" – Requests Data from Server as read on Client Buffered in packets at network level Buffered in packets at network level – Holds state on the Server until closed Pessimistic Concurrency Pessimistic Concurrency – Locking records when read ensures updates don't fail due to concurrency violations – Kills scalability of application – Supported in ADO.NET through transactions Scrollable Server Cursors Scrollable Server Cursors – Holds State on Server – Round-trip per fetch/update – Generally better handled in DataSet or Stored Procedure – Supported in ADO.NET through Cursor DML commands
9
'Start a transaction and set on Select command Dim connect = adapter.SelectCommand.Connection connect.Open() Dim tran = connect.BeginTransaction(IsolationLevel.Serializable) adapter.SelectCommand.Transaction = tran 'Fill DataSet and make changes adapter.Fill(ds, "Employees") Dim employee As DataRow For Each employee In ds.Tables("Employees").Rows employee("Salary") = employee("Salary") * 1.1 employee("Salary") = employee("Salary") * 1.1Next 'Set the connection and transaction for the update command adapter.UpdateCommand.Connection = connect adapter.UpdateCommand.Transaction = tran adapter.Update(ds,"Employees")tran.Commit()connect.Close() Pessimistic Concurrency
10
' Declare and open cursor Dim cmd As New SqlCommand(Nothing, conn) cmd.CommandText = “DECLARE mycursor SCROLLABLE CURSOR FOR select * from Customers” cmd.ExecuteNonQuery() cmd.CommandText = “OPEN mycursor” cmd.ExecuteNonQuery() ' Read from cursor Dim dr As SqlDataReader cmd.CommandText = “FETCH NEXT FROM mycursor” While(True) dr =cmd.ExecuteReader() if (dr.Read() = false) Then Exit While Console.WriteLine("CompanyName is " & dr("CompanyName")) dr.Close() End While ' Update fifth row cmd.CommandText = “FETCH ABSOLUTE 5 FROM mycursor” cmd.ExecuteNonQuery() cmd.CommandText = “UPDATE Customers set FirstName = ‘Bill’ WHERE CURRENT OF mycursor” cmd.ExecuteNonQuery() ' Close the cursor cmd.CommandText = “CLOSE mycursor; DEALLOCATE mycursor” cmd.ExecuteNonQuery() Scrollable Server Cursors
11
Using The Dataset As A Cache DataSet optimized for multi-threaded read access DataSet optimized for multi-threaded read access – Can put in ASP.NET cache – Doesn't take locks – Need to synchronize writes – Clone, Update, and replace Function GetCategories() As DataSet 'See if DataSet exists in Cache Dim categories As DataSet = Cache("CategoriesDS") if (categories Is Nothing) ' not in cache, create DataAdapter and Load DataSet Dim adapter As new SqlDataAdapter("Select CategoryName from Categories",cnn) adapter.Fill(categories) 'Put Categories Dataset into Cache Cache("CategoriesDS")=categories End If return categories End Function
12
Controlling how XML is Generated DataSet lets you control how XML is generated DataSet lets you control how XML is generated Name, Namespace properties on DataSet, DataTable, DataColumn Name, Namespace properties on DataSet, DataTable, DataColumn MappingType property on DataColumn defines how data is written MappingType property on DataColumn defines how data is written – Element, Attribute, SimpleType, Hidden Nested Property on DataRelation controls how children are written Nested Property on DataRelation controls how children are written
13
Controlling how XML is Generated ' Write out CustomerID, OrderID as Attributes ds.Tables("Customers").Columns("CustomerID").ColumnMapping = MappingType.Attribute ds.Tables("Orders").Columns("OrderID").ColumnMapping = MappingType.Attribute ' Write out Orders as children of Customers ds.Relations("cust_orders").Nested = True <CustomerOrders> Manuel Pereira Manuel Pereira GROSR GROSR 1996-07-30 1996-07-30 </CustomerOrders>
14
Working With Identity Columns Issue: Primary Keys must be unique across consumers in order to merge back to database Issue: Primary Keys must be unique across consumers in order to merge back to database Solution #1: Use a GUID as the Primary Key where possible Solution #1: Use a GUID as the Primary Key where possible – Can be generated on the Client or Server Guaranteed to be unique Guaranteed to be unique – Doesn’t change when updated to the Server No fixup required for child rows No fixup required for child rows
15
Working With Identity Columns Issue: Primary Keys must be unique across consumers in order to merge back to database Issue: Primary Keys must be unique across consumers in order to merge back to database Solution #2: If you are stuck with an AutoIncrement Primary Key… Solution #2: If you are stuck with an AutoIncrement Primary Key… – First, make sure Client value doesn't conflict with Server value Set AutoIncrement Seed, Step to -1 on DataSet Set AutoIncrement Seed, Step to -1 on DataSet – To update values in Dataset, select back the ID in your InsertCommand Update the inserted row with the new value Update the inserted row with the new value – Insert Parent rows before Child Rows Use UpdateRule.Cascade Use UpdateRule.Cascade – If you are merging with the original DataSet, prevent AcceptChanges from being called on Inserted row Specify SkipCurrentRow in OnRowUpdated Eventhandler Specify SkipCurrentRow in OnRowUpdated Eventhandler
16
Sub UpdateData(table As DataTable) ' Set InsertCommand with returned Identity Dim insert As New SqlCommand( _ "Insert into Orders(OrderID,Date) values @OrderID, @Date)" _ & ";Select SCOPE_IDENTITY() as OrderID",cnn) insert.Parameters.Add("@OrderID",SqlDbType.Int).SourceColumn="OrderID" insert.Parameters.Add("@Date",SqlDbType.DateTime).Value = DateTime.Now adapter.InsertCommand = insert ' Set UpdateRowSource and Register RowUpdatedEventHandler insert.UpdatedRowSource = UpdateRowSource.FirstReturnedRecord AddHandler adapter.RowUpdated, _ New SqlRowUpdatedEventHandler(AddressOf myHandler) DataAdapter.Update(table) End Sub Shared Sub myHandler(adapter as Object, e As SqlRowUpdatedEventArgs) ' Don't call AcceptChanges e.Status = UpdateStatus.SkipCurrentRow End Sub Inserting AutoIncrement Values
17
Refreshing Data In The DataSet To update DataSet with current values from the Database values To update DataSet with current values from the Database values – Specify a Primary Key on the Table – Use Adapter.Fill() Fill will update existing values if you have a Primary key Fill will update existing values if you have a Primary key To update original values but preserve changes To update original values but preserve changes – Fill a new DataSet and use DataSet.Merge() with PreserveChanges=true
18
Handling Large ResultSets Select just the data the user needs Select just the data the user needs – User rarely wants to scroll through >100 records Call Cancel() on command to dispose of data beyond what is read Call Cancel() on command to dispose of data beyond what is read Page through large results Page through large results – Use TOP n in SQL Server – Use MaxRows for other databases – Paging by Ordinal range (i.e., records 91-100) – Paging by value range (i.e., M-N) Parameterized Where clause Parameterized Where clause SELECT TOP 10 * FROM (SELECT TOP 100 ProductName, UnitPrice FROM Products ORDER BY UnitPrice ASC) AS Products (SELECT TOP 100 ProductName, UnitPrice FROM Products ORDER BY UnitPrice ASC) AS Products ORDER BY UnitPrice DESC SELECT TOP 10 ProductName, UnitPrice FROM Products WHERE ProductName > @PreviousName ORDER BY ProductName ASC AS Products WHERE ProductName > @PreviousName ORDER BY ProductName ASC AS Products
19
Join Queries Against DataSet Use Relations to navigate from parent to child Use Relations to navigate from parent to child – Restriction: Can’t limit parent based on child values Use XmlDataDocument Use XmlDataDocument – X/Path queries can be hierarchical – Can get DataRows corresponding to returned Elements Dim nodeslist = xmlData.SelectNodes("//Customers/Orders[@State=WA]") Dim customer, order As DataRow For Each customer in CustomerTable.Select("State='WA'") Console.WriteLine("Customer: " & customer("ContactName")) For Each order in customer.GetChildRows("custord") Console.WriteLine("Order Amount = " & order("Amount")) Next Dim node As XmlNode Dim customer as DataRow For Each node in nodelist customer = xmlData.GetRowFromElement(node) Next
20
RecordSet DataSet Getting Data From a RecordSet Getting Data From a RecordSet – Use the OleDbDataAdapter.Fill() method – Persist the RecordSet as XML and load into the DataSet Use an XSL/T for best results Use an XSL/T for best results Getting Data From a DataSet to a RecordSet Getting Data From a DataSet to a RecordSet – Write an XSL Transform to do the conversion We hope to provide one of these in the future We hope to provide one of these in the future – Walk through the DataSet and generate the XDR description then write out the XML in attribute-centric format Sample coming soon… Sample coming soon… Dim rs As New ADODB.Recordset() rs.Open("Select * from Orders", "Data Source=localhost;Integrated Security=true") Dim adapter As New OleDbDataAdapter() adapter.Fill(ds, rs, "Orders") Dim ds As New DataSet() ds.ReadXml("rsOrders.xml)
21
Agenda Common Techniques Common Techniques Optimizing Performance Optimizing Performance – Optimizing Data Retrieval – Using Schema at Design Time – Using Batches – Looking Up Values in the DataSet – Provider specific Optimizations Security Considerations Security Considerations Questions Questions
22
Optimizing Data Retrieval Use ExecuteNonQuery if no results to be returned Use ExecuteNonQuery if no results to be returned – DDL commands,Inserts, Updates, Deletes – Non-result returning Stored Procedures (parameters ok) Return single set of values using Output Parameters Return single set of values using Output Parameters Dim numRowsAffected As Integer = cmd.ExecuteNonQuery() cmd.CommandText = _ "Select @ContactName = ContactName From Customers where CustomerID = 'GROSR'" Dim param = cmd.Parameters.Add("@ContactName",SqlDbType.VarChar,25) param.Direction = ParameterDirection.Output cmd.ExecuteNonQuery() Console.WriteLine("Contact Name = "& param.Value)
23
Efficiently Retrieving BLOBs Use CommandBehavior.SequentialAccess Use CommandBehavior.SequentialAccess – Must retrieve columns in order – No buffering of column values Dim cmd As New SqlCommand( "Select * from Employees", cnn) Dim results = cmd.ExecuteReader(CommandBehavior.SequentialAccess) Dim i As Integer While(results.Read()) For i=0 to results.FieldCount Console.Write("\t "& results(i)) Console.WriteLine()Next End While
24
Use Metadata At Design Time DataReader DataReader – Strongly Typed Ordinal accessors – Dim name As String = dr.GetString(0) DataSet DataSet – Load, don't infer, schema Data Adapter Data Adapter – Don’t use CommandBuilder Specify insert,update,delete commands when known Specify insert,update,delete commands when known – Don’t use CommandBuilder.DeriveParameters() Specify Parameter information when known Specify Parameter information when known – Don’t use MissingSchemaAction.AddWithKey Specify Primary Key information when known Specify Primary Key information when known – custTable.PrimaryKey = custTable.Columns("CustID") – Don’t add Primary Key if not necessary Necessary when Updating,Refreshing,Merging values Necessary when Updating,Refreshing,Merging values
25
Retrieving Multiple Results Specify Batch statement or stored procedure Specify Batch statement or stored procedure Use NextResult() to move to next set of results Use NextResult() to move to next set of results Dim fMoreResults As Boolean = true Dim field As Integer While(fMoreResults) For field = 0 To dr.FieldCount Console.Write("/t"+dr.GetName(field))NextConsole.WriteLine()While(dr.Read()) For field = 0 to dr.FieldCount Console.Write("/t"+dr(field))NextConsole.WriteLine() End While fMoreResults = dr.NextResult() End While
26
Populating Multiple DataTables Retrieve multiple results in a single call Retrieve multiple results in a single call – Execute Batch statement or stored procdure Map results to appropriate tables using tablemappings Map results to appropriate tables using tablemappings Use ExecuteXmlReader to retrieve hierarchical results Use ExecuteXmlReader to retrieve hierarchical results – Load with ReadXml using XmlReadMode.Fragment Submit updates in batches Submit updates in batches – Sample batch update example available soon… – Or save as DiffGram and send to SqlXml Dim adapter As New SqlDataAdapter( _ "SELECT * FROM customers; SELECT * FROM orders",cnn) adapter.TableMappings.Add("Table1","Customer")adapter.TableMappings.Add("Table2","Orders")adapter.Fill(myDataSet)
27
Looking Up Values In The Dataset Searching for Results within a DataSet Searching for Results within a DataSet – DataTable.Find() for searching on PK values Dim customer = customerTable.Rows.Find("GROSR") – DataView.Select() for repeated non-PK queries Sort DataView by search fields Sort DataView by search fields DataView builds an index for sorted columns Dim customerView As New DataView(customerTable) customerView.Sort = "State“ Dim customers = customerView.FindRows("CA") DataView builds an index for sorted columns Dim customerView As New DataView(customerTable) customerView.Sort = "State“ Dim customers = customerView.FindRows("CA") Pass Table, filter, sort, RowState to constructor Dim view As New DataView( _ customerTable,_ "Country=USA",_ "Region",_ DataViewRowState.CurrentRows ) Pass Table, filter, sort, RowState to constructor Dim view As New DataView( _ customerTable,_ "Country=USA",_ "Region",_ DataViewRowState.CurrentRows )
28
Coding To Different Providers Use Activator to create root class (DbConnection) Use Activator to create root class (DbConnection) Code to Interfaces Code to Interfaces Use CreateCommand() to get IDbCommand Use CreateCommand() to get IDbCommand Take into account provider differences Take into account provider differences – SqlClient named parameters versus OLE DB positional parameters – CommandBuilder classes
29
Provider Specific Optimizations SqlClient.NET Data Provider SqlClient.NET Data Provider – Use CommandType.StoredProcedure to execute stored procs More efficient than executing command call{} or Exec syntax More efficient than executing command call{} or Exec syntax – Set max connection lifetime for load balancing Times out valid connections in order to balance across back-ends Times out valid connections in order to balance across back-ends OLE DB.NET Data Provider OLE DB.NET Data Provider – Use specific provider where available For example, the SqlClient.NET Data Provider… For example, the SqlClient.NET Data Provider… – Specify type, size, precision, and scale of parameters Otherwise we rebind w/each execute Otherwise we rebind w/each execute – Connection.State is expensive Round-trip to check state Round-trip to check state Better to listen to change event to track state Better to listen to change event to track state
30
Agenda Common Techniques Common Techniques Optimizing Performance Optimizing Performance Security Considerations Security Considerations – Use Integrated Security – Avoid String Concatenation – Use Stored Procedures – Set Privileges Appropriately Questions Questions
31
Use Integrated Security Don’t use sa account! (especially w/no password) Don’t use sa account! (especially w/no password) connect.ConnectionString = "server=localhost;uid=sa;password=" Don’t embed password in connection string Don’t embed password in connection string connect.ConnectionString = "server=localhost;uid=sa;password=pwd" Don’t concatenate UID/Password from user into connection string (without validating input) Don’t concatenate UID/Password from user into connection string (without validating input) connect.ConnectionString = "server=localhost;uid=sa;password="&pwd – pwd may be “pwd;Default Database = ‘master’” Use Integrated Security Use Integrated Security connect.ConnectionString = "server=localhost;Integrated Security=SSPI"
32
Avoid String Concatenation Don’t concatenate user strings into command text cmd.CommandText = “select * from Customers where CustomerID = "&custID Don’t concatenate user strings into command text cmd.CommandText = “select * from Customers where CustomerID = "&custID – user may set custID = ‘“GROSR’; Drop Table Customers;” Instead Instead – Have user select string from an enumeration, rather than enter free text – Better yet; pass strings as Parameters: cmd.CommandText = “select * from Customers Where CustomerID = @CustID“ cmd.Parameters.Add("@CustID",custID)
33
Use Stored Procedures Controls what data user accesses and how Controls what data user accesses and how Allows privileges to be set on Stored Procedure Allows privileges to be set on Stored Procedure Can enforce additional business logic Can enforce additional business logic Added protection from malicious string concatenation Added protection from malicious string concatenation – Values passed as parameters – Validate strings passed to Stored Procedure
34
Set Privileges Appropriately Create user appropriate to client role Create user appropriate to client role – Don’t just use “sa” for everything! Set Privileges on resources accessed Set Privileges on resources accessed – Stored Procedures – Tables – Columns
35
Whitepapers: Whitepapers: – ADO.NET for the ADO Programmer: http://msdn.microsoft.com/library/en-us/dndotnet/html/ADONETProg.asp http://msdn.microsoft.com/library/en-us/dndotnet/html/ADONETProg.asp – ADO.NET Best Practices (coming soon): http://msdn.microsoft.com/library/en-us/dndotnet/html/ADONETBest.asp http://msdn.microsoft.com/library/en-us/dndotnet/html/ADONETBest.asp ADO.NET On-Line Chat Transcript ADO.NET On-Line Chat Transcripthttp://msdn.microsoft.com/chats/vstudio/vstudio_012402.asp The.NET Show: ADO.NET: The.NET Show: ADO.NET: http://msdn.microsoft.com/theshow/Episode017/default.asp Additional Information
36
Questions?
37
Resources from Microsoft Press For more information please visit the TechEd Bookshop. www.microsoft.com/mspress ADO.NET
38
Don’t forget to complete the on-line Session Feedback form on the Attendee Web site https://web.mseventseurope.com/teched/ https://web.mseventseurope.com/teched/
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.