Advanced dot net

38
DAT402: DAT402: Advanced ADO.NET Advanced ADO.NET Michael Pizzo Michael Pizzo Software Architect Software Architect WebData Team WebData Team Microsoft Corporation Microsoft Corporation

description

Advanced dot net

Transcript of Advanced dot net

Page 1: Advanced dot net

DAT402:DAT402:Advanced ADO.NETAdvanced ADO.NET

Michael PizzoMichael PizzoSoftware ArchitectSoftware ArchitectWebData TeamWebData TeamMicrosoft CorporationMicrosoft Corporation

Page 2: Advanced dot net
Page 3: Advanced dot net

AgendaAgenda Common TechniquesCommon Techniques Optimizing PerformanceOptimizing Performance Security ConsiderationsSecurity Considerations QuestionsQuestions

Page 4: Advanced dot net

AgendaAgenda Common TechniquesCommon Techniques

Updating from a DataSetUpdating from a DataSet Server Cursors and ADO.NETServer Cursors and ADO.NET Using the DataSet as a CacheUsing the DataSet as a Cache Controlling how XML is generatedControlling how XML is generated Working with Identity ColumnsWorking with Identity Columns Handling Large ResultSetsHandling Large ResultSets Join Queries against a DataSetJoin Queries against a DataSet RecordsetRecordsetDatasetDataset

Optimizing PerformanceOptimizing Performance Security ConsiderationsSecurity Considerations

Page 5: Advanced dot net

Updating From A DataSetUpdating From A DataSet Use a DataAdapterUse a DataAdapter

Typically one per table to be updatedTypically one per table to be updated Specify Insert, Update, Delete commandsSpecify Insert, Update, Delete commands

Use CommandBuilder for AdHoc queriesUse CommandBuilder for AdHoc queries Designers, toolsDesigners, tools

Call Update(), passing in Call Update(), passing in DataSet/DataTable to be updatedDataSet/DataTable to be updated No persistent connection between No persistent connection between

DataAdapter and DataSetDataAdapter and DataSet Can use different DataAdapters for Fill and UpdateCan use different DataAdapters for Fill and Update Use ExtendedProperties to pass datasource Use ExtendedProperties to pass datasource

informationinformation

Page 6: Advanced dot net

Specifying Update CommandsSpecifying Update Commands Associate parameters with DataSet ColumnsAssociate parameters with DataSet Columns

Specify SourceColumn propertySpecify SourceColumn property Parameter values will be set using values from the Dataset Parameter values will be set using values from the Dataset

for each Insert, Update, or Deletefor each Insert, Update, or Delete

'Specify Delete Command'Specify Delete CommandDim delete As New SqlCommand("DeleteOrder", cnn)Dim delete As New SqlCommand("DeleteOrder", cnn)delete.CommandType = CommandType.StoredProceduredelete.CommandType = CommandType.StoredProcedure

'Create a Parameter and associate it with Dataset column'Create a Parameter and associate it with Dataset columnDim param As New SqlParameter("@OrderID", SqlDbType.Int)Dim param As New SqlParameter("@OrderID", SqlDbType.Int)param.SourceColumn = "OrderID"param.SourceColumn = "OrderID"delete.Parameters.Add(param)delete.Parameters.Add(param)

'Set as the Delete Command'Set as the Delete Commandadapter.DeleteCommand = deleteadapter.DeleteCommand = delete

Page 7: Advanced dot net

Dim adapter As New SqlDataAdapter()Dim adapter As New SqlDataAdapter()Dim delete As New SqlCommand("DeleteOrder", cnn)Dim delete As New SqlCommand("DeleteOrder", cnn)delete.CommandType = CommandType.StoredProceduredelete.CommandType = CommandType.StoredProceduredelete.Parameters.Add("@OrderID", SqlDbType.Int).SourceColumn = "OrderID"delete.Parameters.Add("@OrderID", SqlDbType.Int).SourceColumn = "OrderID"adapter.DeleteCommand = deleteadapter.DeleteCommand = deleteDim insert As New SqlCommand("AddOrder", cnn)Dim insert As New SqlCommand("AddOrder", cnn)insert.CommandType = CommandType.StoredProcedureinsert.CommandType = CommandType.StoredProcedureinsert.Parameters.Add("@OrderID", SqlDbType.Int).SourceColumn = "OrderID"insert.Parameters.Add("@OrderID", SqlDbType.Int).SourceColumn = "OrderID"insert.Parameters.Add("@CustD", SqlDbType.Int).SourceColumn = "CustomerID"insert.Parameters.Add("@CustD", SqlDbType.Int).SourceColumn = "CustomerID"insert.Parameters.Add("@Date", SqlDbType.DateTime).Value = DateTime.Nowinsert.Parameters.Add("@Date", SqlDbType.DateTime).Value = DateTime.Nowadapter.InsertCommand = insertadapter.InsertCommand = insertDim update As New SqlCommand("UpdateOrder", cnn)Dim update As New SqlCommand("UpdateOrder", cnn)update.CommandType = CommandType.StoredProcedureupdate.CommandType = CommandType.StoredProcedureupdate.Parameters.Add("@OrderID",SqlDbType.Int).SourceColumn="OrderID"update.Parameters.Add("@OrderID",SqlDbType.Int).SourceColumn="OrderID"update.Parameters.Add("@CustD",SqlDbType.Int).SourceColumn="CustomerID"update.Parameters.Add("@CustD",SqlDbType.Int).SourceColumn="CustomerID"adapter.UpdateCommand = updateadapter.UpdateCommand = updateadapter.Update(ordersTable)adapter.Update(ordersTable)

Updating ExampleUpdating Example

Page 8: Advanced dot net

Optimistic ConcurrencyOptimistic Concurrency Specify Original values or RowVersion columnSpecify Original values or RowVersion column

Original values for changes made to data readOriginal values for changes made to data read RowVersion for any changes made to rowRowVersion for any changes made to row

Set SourceVersion for original valuesSet SourceVersion for original values

Account for Nulls in Where clause:Account for Nulls in Where clause:

Add additional logic in Stored Procedure for Add additional logic in Stored Procedure for handling concurrency and conflictshandling concurrency and conflicts

WHERE ((Country ISNULL) AND (@Country ISNULL)) OR (Country=@Country)WHERE ((Country ISNULL) AND (@Country ISNULL)) OR (Country=@Country)

Dim update As New SqlCommand("Update Customers (Name) Values " & _ Dim update As New SqlCommand("Update Customers (Name) Values " & _ "(@Name) Where Name=@OldName AND CustID=@ID",cnn)"(@Name) Where Name=@OldName AND CustID=@ID",cnn)

update.Parameters.Add("@Name",SqlDbType.VarChar).SourceColumn = "Name"update.Parameters.Add("@Name",SqlDbType.VarChar).SourceColumn = "Name"update.Parameters.Add("@CustID",SqlDbType.Int).SourceColumn = "CustomerID"update.Parameters.Add("@CustID",SqlDbType.Int).SourceColumn = "CustomerID"Dim param = update.Parameters.Add("@OldName",SqlDbType.VarChar)Dim param = update.Parameters.Add("@OldName",SqlDbType.VarChar)param.SourceColumn = "Name"param.SourceColumn = "Name"param.SourceVersion = DataRowVersion.Originalparam.SourceVersion = DataRowVersion.Original

Page 9: Advanced dot net

Server Cursors And ADO.NETServer Cursors And ADO.NET DataReader versus DataSetDataReader versus DataSet

DataReader is a Forward Only/Read Only "Server Cursor"DataReader is a Forward Only/Read Only "Server Cursor" Requests Data from Server as read on ClientRequests Data from Server as read on Client

Buffered in packets at network levelBuffered in packets at network level Holds state on the Server until closedHolds state on the Server until closed

Pessimistic ConcurrencyPessimistic Concurrency Locking records when read ensures updates don't fail due to Locking records when read ensures updates don't fail due to

concurrency violationsconcurrency violations Kills scalability of applicationKills scalability of application Supported in ADO.NET through transactionsSupported in ADO.NET through transactions

Scrollable Server CursorsScrollable Server Cursors Holds State on ServerHolds State on Server Round-trip per fetch/updateRound-trip per fetch/update Generally better handled in DataSet or Stored ProcedureGenerally better handled in DataSet or Stored Procedure Supported in ADO.NET through Cursor DML commandsSupported in ADO.NET through Cursor DML commands

Page 10: Advanced dot net

'Start a transaction and set on Select command'Start a transaction and set on Select commandDim connect = adapter.SelectCommand.ConnectionDim connect = adapter.SelectCommand.Connectionconnect.Open()connect.Open()Dim tran = connect.BeginTransaction(IsolationLevel.Serializable)Dim tran = connect.BeginTransaction(IsolationLevel.Serializable)adapter.SelectCommand.Transaction = tranadapter.SelectCommand.Transaction = tran'Fill DataSet and make changes'Fill DataSet and make changesadapter.Fill(ds, "Employees")adapter.Fill(ds, "Employees")Dim employee As DataRowDim employee As DataRowFor Each employee In ds.Tables("Employees").RowsFor Each employee In ds.Tables("Employees").Rows employee("Salary") = employee("Salary") * 1.1employee("Salary") = employee("Salary") * 1.1NextNext'Set the connection and transaction for the update command'Set the connection and transaction for the update commandadapter.UpdateCommand.Connection = connectadapter.UpdateCommand.Connection = connectadapter.UpdateCommand.Transaction = tranadapter.UpdateCommand.Transaction = tranadapter.Update(ds,"Employees")adapter.Update(ds,"Employees")tran.Commit()tran.Commit()connect.Close()connect.Close()

Pessimistic ConcurrencyPessimistic Concurrency

Page 11: Advanced dot net

' Declare and open cursor' Declare and open cursorDim cmd As New SqlCommand(Nothing, conn)Dim cmd As New SqlCommand(Nothing, conn)cmd.CommandText = “DECLARE mycursor SCROLLABLE CURSOR FOR select * from Customers”cmd.CommandText = “DECLARE mycursor SCROLLABLE CURSOR FOR select * from Customers”cmd.ExecuteNonQuery()cmd.ExecuteNonQuery()cmd.CommandText = “OPEN mycursor”cmd.CommandText = “OPEN mycursor”cmd.ExecuteNonQuery()cmd.ExecuteNonQuery()

' Read from cursor' Read from cursorDim dr As SqlDataReaderDim dr As SqlDataReadercmd.CommandText = “FETCH NEXT FROM mycursor”cmd.CommandText = “FETCH NEXT FROM mycursor”While(True)While(True)

dr =cmd.ExecuteReader()dr =cmd.ExecuteReader()if (dr.Read() = false) Then Exit Whileif (dr.Read() = false) Then Exit WhileConsole.WriteLine("CompanyName is " & dr("CompanyName"))Console.WriteLine("CompanyName is " & dr("CompanyName"))dr.Close()dr.Close()

End WhileEnd While

' Update fifth row' Update fifth rowcmd.CommandText = “FETCH ABSOLUTE 5 FROM mycursor”cmd.CommandText = “FETCH ABSOLUTE 5 FROM mycursor”cmd.ExecuteNonQuery()cmd.ExecuteNonQuery()cmd.CommandText = “UPDATE Customers set FirstName = ‘Bill’ WHERE CURRENT OF mycursor”cmd.CommandText = “UPDATE Customers set FirstName = ‘Bill’ WHERE CURRENT OF mycursor”cmd.ExecuteNonQuery()cmd.ExecuteNonQuery()

' Close the cursor' Close the cursorcmd.CommandText = “CLOSE mycursor; DEALLOCATE mycursor”cmd.CommandText = “CLOSE mycursor; DEALLOCATE mycursor”cmd.ExecuteNonQuery()cmd.ExecuteNonQuery()

Scrollable Server CursorsScrollable Server Cursors

Page 12: Advanced dot net

Using The Dataset As A CacheUsing The Dataset As A Cache

Function GetCategories() As DataSetFunction GetCategories() As DataSet'See if DataSet exists in Cache'See if DataSet exists in CacheDim categories As DataSet = Cache("CategoriesDS")Dim categories As DataSet = Cache("CategoriesDS")if (categories Is Nothing) ' not in cacheif (categories Is Nothing) ' not in cache

'Create DataAdapter and Load DataSet'Create DataAdapter and Load DataSetDim adapter As new SqlDataAdapter( _Dim adapter As new SqlDataAdapter( _

"Select CategoryName from Categories",cnn)"Select CategoryName from Categories",cnn)adapter.Fill(categories)adapter.Fill(categories)'Put Categories Dataset into Cache'Put Categories Dataset into CacheCache("CategoriesDS")=categoriesCache("CategoriesDS")=categories

End IfEnd Ifreturn categoriesreturn categories

End FunctionEnd Function

DataSet optimized for multi-threaded read accessDataSet optimized for multi-threaded read access Can put in ASP.NET cacheCan put in ASP.NET cache Doesn't take locksDoesn't take locks Need to synchronize writesNeed to synchronize writes Clone, Update, and replaceClone, Update, and replace

Page 13: Advanced dot net

Controlling How The XML Is GeneratedControlling How The XML Is Generated DataSet lets you control how XML is generatedDataSet lets you control how XML is generated Name, Namespace properties on DataSet, DataTable, DataColumnName, Namespace properties on DataSet, DataTable, DataColumn MappingType property on DataColumn defines how data is writtenMappingType property on DataColumn defines how data is written

Element, Attribute, SimpleType, HiddenElement, Attribute, SimpleType, Hidden Nested Property on DataRelation controls how children are writtenNested Property on DataRelation controls how children are written

' Write out CustomerID, OrderID as Attributes' Write out CustomerID, OrderID as Attributesds.Tables("Customers").Columns("CustomerID").ColumnMapping = MappingType.Attributeds.Tables("Customers").Columns("CustomerID").ColumnMapping = MappingType.Attributeds.Tables("Orders").Columns("OrderID").ColumnMapping = MappingType.Attributeds.Tables("Orders").Columns("OrderID").ColumnMapping = MappingType.Attribute

' Write out Orders as children of Customers' Write out Orders as children of Customersds.Relations("cust_orders").Nested = Trueds.Relations("cust_orders").Nested = True <?xml version="1.0" standalone="yes"?><?xml version="1.0" standalone="yes"?>

<CustomerOrders><CustomerOrders> <Customers CustomerID="GROSR"><Customers CustomerID="GROSR"> <ContactName>Manuel Pereira</ContactName><ContactName>Manuel Pereira</ContactName> <Orders OrderID="10268"><Orders OrderID="10268"> <CustomerID>GROSR</CustomerID><CustomerID>GROSR</CustomerID> <OrderDate>1996-07-30</OrderDate><OrderDate>1996-07-30</OrderDate> </Orders></Orders> </Customers></Customers></CustomerOrders></CustomerOrders>

Page 14: Advanced dot net

Working With Identity Working With Identity ColumnsColumnsIssue: Primary Keys must be unique across Issue: Primary Keys must be unique across

consumers in order to merge back to consumers in order to merge back to databasedatabase

Solution #1: Use a GUID as the Primary Solution #1: Use a GUID as the Primary Key where possibleKey where possible Can be generated on the Client or ServerCan be generated on the Client or Server

Guaranteed to be uniqueGuaranteed to be unique Doesn’t change when updated to the ServerDoesn’t change when updated to the Server

No fixup required for child rowsNo fixup required for child rows

Page 15: Advanced dot net

Issue: Primary Keys must be unique across consumers in Issue: Primary Keys must be unique across consumers in order to merge back to databaseorder to merge back to database

Solution #2: If you are stuck with an AutoIncrement Solution #2: If you are stuck with an AutoIncrement Primary Key…Primary Key… First, make sure Client value doesn't conflict with Server valueFirst, make sure Client value doesn't conflict with Server value

Set AutoIncrement Seed, Step to -1 on DataSetSet AutoIncrement Seed, Step to -1 on DataSet To update values in Dataset, select back the ID in your To update values in Dataset, select back the ID in your

InsertCommandInsertCommand Update the inserted row with the new valueUpdate the inserted row with the new value

Insert Parent rows before Child RowsInsert Parent rows before Child Rows Use UpdateRule.CascadeUse UpdateRule.Cascade

If you are merging with the original DataSet, prevent If you are merging with the original DataSet, prevent AcceptChanges from being called on Inserted rowAcceptChanges from being called on Inserted row Specify SkipCurrentRow in OnRowUpdated EventhandlerSpecify SkipCurrentRow in OnRowUpdated Eventhandler

Working With Identity Working With Identity ColumnsColumns

Page 16: Advanced dot net

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 AcceptChangese.Status = UpdateStatus.SkipCurrentRow

End Sub

Inserting AutoIncrement ValuesInserting AutoIncrement Values

Page 17: Advanced dot net

Refreshing Data In The DataSetRefreshing Data In The DataSet To update DataSet with current To update DataSet with current

values from the Database valuesvalues from the Database values Specify a Primary Key on the TableSpecify a Primary Key on the Table Use Adapter.Fill()Use Adapter.Fill()

Fill will update existing values if you have Fill will update existing values if you have a Primary keya Primary key

To update original values but To update original values but preserve changespreserve changes Fill a new DataSet and use Fill a new DataSet and use

DataSet.Merge() with DataSet.Merge() with PreserveChanges=truePreserveChanges=true

Page 18: Advanced dot net

Handling Large ResultSetsHandling Large ResultSets Select just the data the user needsSelect just the data the user needs

User rarely wants to scroll through >100 recordsUser rarely wants to scroll through >100 records Call Cancel() on command to dispose of data Call Cancel() on command to dispose of data

beyond what is readbeyond what is read Page through large resultsPage through large results

Use TOP n in SQL ServerUse TOP n in SQL Server Use MaxRows for other databasesUse MaxRows for other databasesPaging by Ordinal range (i.e., records 91-100)Paging by Ordinal range (i.e., records 91-100)

Paging by value range (i.e., M-N)Paging by value range (i.e., M-N) Parameterized Where clauseParameterized Where clause

SELECT TOP 10 * FROM 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 ProductsORDER BY UnitPrice DESCORDER BY UnitPrice DESC

SELECT TOP 10 ProductName, UnitPrice FROM Products SELECT TOP 10 ProductName, UnitPrice FROM Products WHERE ProductName > @PreviousName ORDER BY ProductName ASC AS ProductsWHERE ProductName > @PreviousName ORDER BY ProductName ASC AS Products

Page 19: Advanced dot net

Join Queries Against DataSetJoin Queries Against DataSet Use Relations to navigate from parent to childUse Relations to navigate from parent to child

Restriction: Can’t limit parent based on child valuesRestriction: Can’t limit parent based on child values Use XmlDataDocumentUse XmlDataDocument

X/Path queries can be hierarchicalX/Path queries can be hierarchical

Can get DataRows corresponding to returned ElementsCan get DataRows corresponding to returned ElementsDim nodeslist = xmlData.SelectNodes("//Customers/Orders[@State=WA]")

Dim customer, order As DataRowFor 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"))

NextNext

Dim node As XmlNodeDim customer as DataRowFor Each node in nodelist

customer = xmlData.GetRowFromElement(node)Next

Page 20: Advanced dot net

RecordSet RecordSet DataSetDataSet Getting Data From a RecordSetGetting Data From a RecordSet

Use the OleDbDataAdapter.Fill() methodUse the OleDbDataAdapter.Fill() method

Persist the RecordSet as XML and load into the DataSetPersist the RecordSet as XML and load into the DataSet Use an XSL/T for best resultsUse an XSL/T for best results

Getting Data From a DataSet to a RecordSetGetting Data From a DataSet to a RecordSet Write an XSL Transform to do the conversionWrite an XSL Transform to do the conversion

We hope to provide one of these in the futureWe hope to provide one of these in the future Walk through the DataSet and generate the XDR description Walk through the DataSet and generate the XDR description

then write out the XML in attribute-centric formatthen write out the XML in attribute-centric format Sample coming soon…Sample coming soon…

Dim rs As New ADODB.Recordset() Dim rs As New ADODB.Recordset() rs.Open("Select * from Orders", "Data Source=localhost;Integrated Security=true")rs.Open("Select * from Orders", "Data Source=localhost;Integrated Security=true")Dim adapter As New OleDbDataAdapter()Dim adapter As New OleDbDataAdapter()adapter.Fill(ds, rs, "Orders")adapter.Fill(ds, rs, "Orders")

Dim ds As New DataSet()Dim ds As New DataSet()ds.ReadXml("rsOrders.xml)ds.ReadXml("rsOrders.xml)

Page 21: Advanced dot net

AgendaAgenda Common TechniquesCommon Techniques Optimizing PerformanceOptimizing Performance

Optimizing Data RetrievalOptimizing Data Retrieval Using Schema at Design TimeUsing Schema at Design Time Using BatchesUsing Batches Looking Up Values in the DataSetLooking Up Values in the DataSet Provider specific OptimizationsProvider specific Optimizations

Security ConsiderationsSecurity Considerations QuestionsQuestions

Page 22: Advanced dot net

Optimizing Data RetrievalOptimizing Data Retrieval Use ExecuteNonQuery if no results to be returnedUse ExecuteNonQuery if no results to be returned

DDL commands,Inserts, Updates, DeletesDDL commands,Inserts, Updates, Deletes Non-result returning Stored Procedures (parameters ok)Non-result returning Stored Procedures (parameters ok)

Return single set of values using Output ParametersReturn single set of values using Output Parameters

Dim numRowsAffected As Integer = cmd.ExecuteNonQuery()Dim numRowsAffected As Integer = cmd.ExecuteNonQuery()

cmd.CommandText = _cmd.CommandText = _ "Select @ContactName = ContactName From Customers where CustomerID = 'GROSR'""Select @ContactName = ContactName From Customers where CustomerID = 'GROSR'" Dim param = cmd.Parameters.Add("@ContactName",SqlDbType.VarChar,25)Dim param = cmd.Parameters.Add("@ContactName",SqlDbType.VarChar,25) param.Direction = ParameterDirection.Outputparam.Direction = ParameterDirection.Output cmd.ExecuteNonQuery()cmd.ExecuteNonQuery() Console.WriteLine("Contact Name = "& param.Value)Console.WriteLine("Contact Name = "& param.Value)

Page 23: Advanced dot net

Efficiently Retrieving BLOBsEfficiently Retrieving BLOBs Use CommandBehavior.SequentialAccessUse CommandBehavior.SequentialAccess

Must retrieve columns in orderMust retrieve columns in order No buffering of column valuesNo buffering of column values

Dim cmd As New SqlCommand( "Select * from Employees", cnn)Dim cmd As New SqlCommand( "Select * from Employees", cnn)Dim results = cmd.ExecuteReader(CommandBehavior.SequentialAccess)Dim results = cmd.ExecuteReader(CommandBehavior.SequentialAccess)Dim i As IntegerDim i As IntegerWhile(results.Read()) While(results.Read())

For i=0 to results.FieldCountFor i=0 to results.FieldCountConsole.Write("\t "& results(i))Console.Write("\t "& results(i))Console.WriteLine()Console.WriteLine()

NextNextEnd WhileEnd While

Page 24: Advanced dot net

Use Metadata At Design Time Use Metadata At Design Time DataReaderDataReader

Strongly Typed Ordinal accessorsStrongly Typed Ordinal accessorsDim name As String = dr.GetString(0)Dim name As String = dr.GetString(0)

DataSetDataSet Load, don't infer, schemaLoad, don't infer, schema

Data AdapterData Adapter Don’t use CommandBuilderDon’t use CommandBuilder

Specify insert,update,delete commands when knownSpecify insert,update,delete commands when known Don’t use CommandBuilder.DeriveParameters()Don’t use CommandBuilder.DeriveParameters()

Specify Parameter information when knownSpecify Parameter information when known Don’t use MissingSchemaAction.AddWithKeyDon’t use MissingSchemaAction.AddWithKey

Specify Primary Key information when knownSpecify Primary Key information when known custTable.PrimaryKey = custTable.Columns("CustomerID")custTable.PrimaryKey = custTable.Columns("CustomerID") Don’t add Primary Key if not necessaryDon’t add Primary Key if not necessary

Necessary when Updating,Refreshing,Merging valuesNecessary when Updating,Refreshing,Merging values

Page 25: Advanced dot net

Retrieving Multiple ResultsRetrieving Multiple Results Specify Batch statement or stored procedureSpecify Batch statement or stored procedure Use NextResult() to move to next set of resultsUse NextResult() to move to next set of resultsDim fMoreResults As Boolean = trueDim fMoreResults As Boolean = trueDim field As IntegerDim field As IntegerWhile(fMoreResults) While(fMoreResults)

For field = 0 To dr.FieldCount For field = 0 To dr.FieldCount Console.Write("/t"+dr.GetName(field)) Console.Write("/t"+dr.GetName(field))

NextNextConsole.WriteLine()Console.WriteLine()While(dr.Read())While(dr.Read())

For field = 0 to dr.FieldCountFor field = 0 to dr.FieldCountConsole.Write("/t"+dr(field))Console.Write("/t"+dr(field))

NextNextConsole.WriteLine()Console.WriteLine()

End WhileEnd WhilefMoreResults = dr.NextResult()fMoreResults = dr.NextResult()

End WhileEnd While

Page 26: Advanced dot net

Populating Multiple DataTablesPopulating Multiple DataTables Retrieve multiple results in a single callRetrieve multiple results in a single call

Execute Batch statement or stored procdureExecute Batch statement or stored procdure Map results to appropriate tables using tablemappingsMap results to appropriate tables using tablemappings

Use ExecuteXmlReader to retrieve Use ExecuteXmlReader to retrieve hierarchical resultshierarchical results

Load with ReadXml using XmlReadMode.FragmentLoad with ReadXml using XmlReadMode.Fragment

Submit updates in batchesSubmit updates in batches Sample batch update example available soon…Sample batch update example available soon… Or save as DiffGram and send to SqlXmlOr save as DiffGram and send to SqlXml

Dim adapter As New SqlDataAdapter( _Dim adapter As New SqlDataAdapter( _"SELECT * FROM customers; SELECT * FROM orders",cnn)"SELECT * FROM customers; SELECT * FROM orders",cnn)

adapter.TableMappings.Add("Table1","Customer")adapter.TableMappings.Add("Table1","Customer")adapter.TableMappings.Add("Table2","Orders")adapter.TableMappings.Add("Table2","Orders")adapter.Fill(myDataSet)adapter.Fill(myDataSet)

Page 27: Advanced dot net

Looking Up Values In The DatasetLooking Up Values In The Dataset Searching for Results within a DataSetSearching for Results within a DataSet

DataTable.Find() for searching on PK valuesDataTable.Find() for searching on PK values

DataView.Select() for repeated non-PK queriesDataView.Select() for repeated non-PK queries Sort DataView by search fieldsSort DataView by search fields DataView builds an index for sorted columnsDataView builds an index for sorted columns

Pass Table, filter, sort, RowState to constructorPass Table, filter, sort, RowState to constructor

Dim customer = customerTable.Rows.Find("GROSR")Dim customer = customerTable.Rows.Find("GROSR")

Dim customerView As New DataView(customerTable)Dim customerView As New DataView(customerTable)customerView.Sort = "State"customerView.Sort = "State"Dim customers = customerView.FindRows("CA")Dim customers = customerView.FindRows("CA")

Dim view As New DataView( Dim view As New DataView( __customerTable,customerTable, __"Country=USA","Country=USA", __"Region","Region", __

DataViewRowState.CurrentRows )DataViewRowState.CurrentRows )

Page 28: Advanced dot net

Coding To Different ProvidersCoding To Different Providers Use Activator to create root class Use Activator to create root class

(DbConnection)(DbConnection) Code to InterfacesCode to Interfaces Use CreateCommand() to get Use CreateCommand() to get

IDbCommandIDbCommand Take into account provider differencesTake into account provider differences

SqlClient named parameters versus OLE SqlClient named parameters versus OLE DB positional parametersDB positional parameters

CommandBuilder classesCommandBuilder classes

Page 29: Advanced dot net

Provider Specific OptimizationsProvider Specific Optimizations SqlClient .NET Data ProviderSqlClient .NET Data Provider

Use CommandType.StoredProcedure to execute stored procsUse CommandType.StoredProcedure to execute stored procs More efficient than executing command call{} or Exec syntaxMore efficient than executing command call{} or Exec syntax

Set max connection lifetime for load balancingSet max connection lifetime for load balancing Times out valid connections in order to balance across back-endsTimes out valid connections in order to balance across back-ends

OLE DB .NET Data ProviderOLE DB .NET Data Provider Use specific provider where availableUse 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 parametersSpecify type, size, precision, and scale of parameters

Otherwise we rebind w/each executeOtherwise we rebind w/each execute Connection.State is expensiveConnection.State is expensive

Round-trip to check stateRound-trip to check state Better to listen to change event to track stateBetter to listen to change event to track state

Page 30: Advanced dot net

AgendaAgenda Common TechniquesCommon Techniques Optimizing PerformanceOptimizing Performance Security ConsiderationsSecurity Considerations

Use Integrated SecurityUse Integrated Security Avoid String ConcatenationAvoid String Concatenation Use Stored ProceduresUse Stored Procedures Set Privileges AppropriatelySet Privileges Appropriately

QuestionsQuestions

Page 31: Advanced dot net

Use Integrated SecurityUse Integrated Security Don’t use sa account! (especially w/no Don’t use sa account! (especially w/no

password)password)connect.ConnectionString = "server=localhost;uid=sa;password="connect.ConnectionString = "server=localhost;uid=sa;password="

Don’t embed password in connection stringDon’t embed password in connection stringconnect.ConnectionString = "server=localhost;uid=sa;password=pwd"connect.ConnectionString = "server=localhost;uid=sa;password=pwd"

Don’t concatenate UID/Password from user Don’t concatenate UID/Password from user into connection string (without validating into connection string (without validating input)input)connect.ConnectionString = "server=localhost;uid=sa;password="&pwdconnect.ConnectionString = "server=localhost;uid=sa;password="&pwd

pwd may be “pwd;Default Database = ‘master’”pwd may be “pwd;Default Database = ‘master’” Use Integrated SecurityUse Integrated Security

connect.ConnectionString = "server=localhost;Integrated Security=SSPI"connect.ConnectionString = "server=localhost;Integrated Security=SSPI"

Page 32: Advanced dot net

Avoid String ConcatenationAvoid String Concatenation Don’t concatenate user strings into command Don’t concatenate user strings into command

texttext cmd.CommandText = "Select * from Customers where CustomerID = "&custIDcmd.CommandText = "Select * from Customers where CustomerID = "&custID

user may set custID = ‘“GROSR’; Drop Table user may set custID = ‘“GROSR’; Drop Table Customers;”Customers;”

InsteadInstead Have user select string from an enumeration, Have user select string from an enumeration,

rather than enter free textrather than enter free text Better yet; pass strings as Parameters:Better yet; pass strings as Parameters: cmd.CommandText = "Select * from Customers Where CustomerID = @CustID"cmd.CommandText = "Select * from Customers Where CustomerID = @CustID" cmd.Parameters.Add("@CustID",custID)cmd.Parameters.Add("@CustID",custID)

Page 33: Advanced dot net

Use Stored ProceduresUse Stored Procedures Controls what data user accesses Controls what data user accesses

and howand how Allows privileges to be set on Allows privileges to be set on

Stored ProcedureStored Procedure Can enforce additional business logicCan enforce additional business logic Added protection from malicious Added protection from malicious

string concatenationstring concatenation Values passed as parametersValues passed as parameters Validate strings passed to Stored Validate strings passed to Stored

ProcedureProcedure

Page 34: Advanced dot net

Set Privileges AppropriatelySet Privileges Appropriately Create user appropriate to client roleCreate user appropriate to client role

Don’t just use “sa” for everything!Don’t just use “sa” for everything! Set Privileges on resources accessedSet Privileges on resources accessed

Stored ProceduresStored Procedures TablesTables ColumnsColumns

Page 35: Advanced dot net

Additional InformationAdditional Information Whitepapers:Whitepapers:

ADO.NET for the ADO Programmer:ADO.NET for the ADO Programmer: http://msdn.microsoft.com/library/en-us/dndotnet/html/ADONETProg.asphttp://msdn.microsoft.com/library/en-us/dndotnet/html/ADONETProg.asp

ADO.NET Best Practices (coming soon):ADO.NET Best Practices (coming soon): http://msdn.microsoft.com/library/en-us/dndotnet/html/ADONETBest.asphttp://msdn.microsoft.com/library/en-us/dndotnet/html/ADONETBest.asp

ADO.NET On-Line Chat TranscriptADO.NET On-Line Chat Transcripthttp://msdn.microsoft.com/chats/vstudio/vstudio_012402.asphttp://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.asphttp://msdn.microsoft.com/theshow/Episode017/default.asp

Page 36: Advanced dot net

Questions?Questions?

Page 37: Advanced dot net

MSDN Architecture MSDN Architecture FastTrackFastTrack FastTrack sessions and reading listFastTrack sessions and reading list

http://www.mymsevents.com/http://www.mymsevents.com/MyMSEvents/Content.aspx?p=fast.htmMyMSEvents/Content.aspx?p=fast.htm

Comments on the FastTrack?Comments on the FastTrack? Please write on back of your review formPlease write on back of your review form

Contact [email protected] [email protected] Related content on Related content on

http://msdn.microsoft.com/BDAdotNEhttp://msdn.microsoft.com/BDAdotNETT

Page 38: Advanced dot net

© 2002 Microsoft Corporation. All rights reserved.© 2002 Microsoft Corporation. All rights reserved.This presentation is for informational purposes only. Microsoft makes no warranties, express or implied, in this summary.This presentation is for informational purposes only. Microsoft makes no warranties, express or implied, in this summary.