Download presentation
Presentation is loading. Please wait.
Published byByron Owen Modified over 9 years ago
1
ADO.NET Tips and Tricks How to get the most out of your data access…
2
Who I Am Shawn Wildermuth (swildermuth@adoguy.com) Independent Consultant (http://adoguy.com) C# MVP INETA Speaker Book Author – “Pragmatic ADO.NET”; MCSD.NET Editor of http://ONDotnet.com This Presentation can be found at: – http://adoguy.com/presentations Shawn Wildermuth (swildermuth@adoguy.com) Independent Consultant (http://adoguy.com) C# MVP INETA Speaker Book Author – “Pragmatic ADO.NET”; MCSD.NET Editor of http://ONDotnet.com This Presentation can be found at: – http://adoguy.com/presentations
3
Overview Can you do ADO.NET Wrong? Unmanaged Resources Connections DataSets Typed DataSets CommandBuilders DataAdapters DataSets & ASP.NET Distributed DataSets Transactions Vendor Neutral Code Can you do ADO.NET Wrong? Unmanaged Resources Connections DataSets Typed DataSets CommandBuilders DataAdapters DataSets & ASP.NET Distributed DataSets Transactions Vendor Neutral Code
4
Are You Doing Anything Wrong? Can you write bad ADO.NET Code? Yes…but: – It is usually intuitive about what is right – Disconnected nature makes it harder to break Areas of confusion about ADO.NET – Easier to scale, but not fool-proof – Disconnected does not mean scalable – Concurrency is harder than older systems (e.g. ADO) – “Why Can’t I Lock Rows” Can you write bad ADO.NET Code? Yes…but: – It is usually intuitive about what is right – Disconnected nature makes it harder to break Areas of confusion about ADO.NET – Easier to scale, but not fool-proof – Disconnected does not mean scalable – Concurrency is harder than older systems (e.g. ADO) – “Why Can’t I Lock Rows”
5
Unmanaged Resources Most ADO.NET objects are IDisposable – Make sure and Dispose() – Inheritance from Component means Dispose() – Not disposing objects will cause leaky code Most ADO.NET objects are IDisposable – Make sure and Dispose() – Inheritance from Component means Dispose() – Not disposing objects will cause leaky code SqlConnection conn = new SqlConnection("..."); SqlDbCommand cmd = conn.CreateCommand(); cmd.CommandText = "..."; conn.Open(); SqlDataReader rdr = cmd.ExecuteReader(); while (rdr.Read()) { Console.WriteLine(rdr.GetString(0)); } conn.Close(); // potential leaky code even though you closed the connection!
6
Unmanaged Resources (2) In C#, use “using” – Forces Dispose to be called automagically – Can be stacked for multiple items – Use try…finally to close connections In C#, use “using” – Forces Dispose to be called automagically – Can be stacked for multiple items – Use try…finally to close connections using (SqlConnection conn = new SqlConnection("...")) using (SqlCommand cmd = conn.CreateConnection) { try { cmd.CommandText = "..."; conn.Open(); using (SqlDataReader rdr = cmd.ExecuteReader()) { while (rdr.Read()) { Console.WriteLine(rdr.GetString(0)); } } // Reader is disposed } finally { conn.Close() } } // using statements ensure Disposed is called
7
Unmanaged Resources (3) In VB.NET, use Try…Finally – No “using” in VB.NET, so must do it all in finally – Ensures always disposed, even if exception In VB.NET, use Try…Finally – No “using” in VB.NET, so must do it all in finally – Ensures always disposed, even if exception Dim conn as new SqlConnection("...") Dim cmd as SqlCommand = conn.CreateConnection Try cmd.CommandText = "..." conn.Open() Dim rdr as SqlDataReader = cmd.ExecuteReader() While rdr.Read() = True Console.WriteLine(rdr.GetString(0)) End While Finally ' Clean Up conn.Close() rdr.Dispose() cmd.Dispose() conn.Dispose() End Try
8
Connections Connections are precious – In DataReaders, let it close it when it is done: Connections are precious – In DataReaders, let it close it when it is done: try { conn.Open(); SqlDataReader rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection); while (rdr.Read()) { // Closes Here on last read Console.WriteLine(rdr.GetString(0)); } } finally { // Make sure we didn’t throw an exception and leak a connection conn.Close(); }
9
Connections (2) Connections are still precious – With DataSets, never open them: Connections are still precious – With DataSets, never open them: DataSet ds = new DataSet; SqlDbConnection conn = new SqlConnection(...); SqlDataAdapter adapter = new SqlDataAdapter(...); // The adapter will always preserve the state // of the connection during the fill // No Need to Open Or Close the connection because the adapter will // close it as soon as possible since it is already closed adapter.Fill(ds); // If it is open, it will leave it open conn.Open(); adapter.Fill(ds); conn.Close();
10
Connections (3) Don’t Hardcode Connection Strings – VS.NET Designer Does it Wrong – Store Them in.Config Files Don’t Hardcode Connection Strings – VS.NET Designer Does it Wrong – Store Them in.Config Files <add key="SqlConnString" value="Server=localhost;Database=Northwind;..." /> <add key="SqlConnString" value="E234998F98A98F..." />
11
Connections (4) Use Connection Factories – Isolates Connection String Storage – Increases Security by Controlling Access Use Connection Factories – Isolates Connection String Storage – Increases Security by Controlling Access using System; using System.Data.OleDb; using System.Configuration; public class ConnectionStrings { public static OleDbConnection GetConnection() { return new OleDbConnection( ConfigurationSettings.AppSettings["ConnString"]); }
12
Connections (5) Secure Connection Strings with Encryption – You could write your own Encryption Library – Better would be if MS supplied one In Windows 2000 and later, use DPAPI DPAPI Eliminates the Key Management Problem Encrypts on a Per Machine or Per User Basis Caveat: May Require Encrypting on Every Machine Described in Detail in a Microsoft PAP: – http://msdn.microsoft.com/library/en-us/dnnetsec/html/SecNetHT07.asp Secure Connection Strings with Encryption – You could write your own Encryption Library – Better would be if MS supplied one In Windows 2000 and later, use DPAPI DPAPI Eliminates the Key Management Problem Encrypts on a Per Machine or Per User Basis Caveat: May Require Encrypting on Every Machine Described in Detail in a Microsoft PAP: – http://msdn.microsoft.com/library/en-us/dnnetsec/html/SecNetHT07.asp
13
DataSets DataSets have full database schema – Tables – Columns – Primary and Foreign Keys – Constraints – Even Triggers Using Full Schema – Allows validation without a network roundtrip – Relationships allows hierarchical view of data DataSets have full database schema – Tables – Columns – Primary and Foreign Keys – Constraints – Even Triggers Using Full Schema – Allows validation without a network roundtrip – Relationships allows hierarchical view of data
14
DataSets (2) Use DataSets for data caching – Most data is not volatile – Saves roundtrips to the database – Less code than writing custom classes Use DataSets for data caching – Most data is not volatile – Saves roundtrips to the database – Less code than writing custom classes public class _default : Page { DataSet _dataSet; const MYDATASET = "MYDATASET"; void OnLoad(...) { if (Session[MYDATASET] == null) { _dataSet = new DataSet(); } else { _dataSet = (DataSet) Session[MYDATASET]; } //... Session[MYDATASET] = _dataSet; }
15
DataSets (3) DataSets can incrementally grow – DataAdapter.Fill adds to DataSet, not replace – Allows cache to be built up as needed DataSets can incrementally grow – DataAdapter.Fill adds to DataSet, not replace – Allows cache to be built up as needed // Fill DataSet with Product #1 adapter.SelectCommand.Parameters["@product"].Value = 1; adapter.Fill(_dataSet);... // Fill DataSet with Product #2 adapter.SelectCommand.Parameters["@product"].Value = 2; adapter.Fill(_dataSet); // Now DataSet has both products in, not just one or the other
16
DataSets (4) Use DataSets for intermittent connectivity – Store locally between times of connectivity – Stored DataSets preserve state of changes – Great for mobile apps (not just CF) Use DataSets for intermittent connectivity – Store locally between times of connectivity – Stored DataSets preserve state of changes – Great for mobile apps (not just CF) public class MainForm : Form { DataSet _dataSet; void OnClose(...) { _dataSet.WriteXml("foo.xml", XmlWriteMode.DiffGram); } void OnLoad(...) { _dataSet.ReadXml("foo.xml", XmlReadMode.DiffGram); }
17
Typed DataSets Use Typed DataSets for Stable Schemas – Data Validate at Compile Time – Improves Developer Productivity with Intellisense – Easier to maintain in light of schema changes than code – Loads XSD Schema in with Code (faster) – Demo Use Typed DataSets for Stable Schemas – Data Validate at Compile Time – Improves Developer Productivity with Intellisense – Easier to maintain in light of schema changes than code – Loads XSD Schema in with Code (faster) – Demo
18
CommandBuilders Good for Simple Optimistic Concurrency – Concurrency based on original values – Robust, but Inefficient – Update and Deletes are huge – No support for Stored Procedures Good for Simple Optimistic Concurrency – Concurrency based on original values – Robust, but Inefficient – Update and Deletes are huge – No support for Stored Procedures DELETE FROM CUSTOMER WHERE ( (CustomerID = @p3) AND ((FirstName IS NULL AND @p4 IS NULL) OR (FirstName = @p5)) AND ((LastName IS NULL AND @p6 IS NULL) OR (LastName = @p7)) AND ((MiddleName IS NULL AND @p8 IS NULL) OR (MiddleName = @p9)) AND ((Address IS NULL AND @p10 IS NULL) OR (Address = @p11)) AND ((Apartment IS NULL AND @p12 IS NULL) OR (Apartment = @p13)) AND ((City IS NULL AND @p14 IS NULL) OR (City = @p15)) AND ((State IS NULL AND @p16 IS NULL) OR (State = @p17)) AND ((Zip IS NULL AND @p18 IS NULL) OR (Zip = @p19)) AND ((HomePhone IS NULL AND @p20 IS NULL) OR (HomePhone = @p21)) AND ((BusinessPhone IS NULL AND @p22 IS NULL) OR (BusinessPhone = @p23)) AND ((DOB IS NULL AND @p24 IS NULL) OR (DOB = @p25)) AND ((Discount IS NULL AND @p26 IS NULL) OR (Discount = @p27)) AND ((CheckedOut IS NULL AND @p28 IS NULL) OR (CheckedOut = @p29)) )
19
CommandBuilders (2) Conclusion – Great for Prototyping – Bad for Production Code – Designer can achieve same at compile time Conclusion – Great for Prototyping – Bad for Production Code – Designer can achieve same at compile time
20
DataAdapters Use different adapters to load and update – Batch Adapters to load multiple tables – Single table adapters to update tables Use Designer Support – Add a Component to project to hold Adapters – Use designer to create Mappings – Get CommandBuilder Behavior at Compile-time – Or Map to Stored Procedures (preferred) Demo Use different adapters to load and update – Batch Adapters to load multiple tables – Single table adapters to update tables Use Designer Support – Add a Component to project to hold Adapters – Use designer to create Mappings – Get CommandBuilder Behavior at Compile-time – Or Map to Stored Procedures (preferred) Demo
21
DataSets & ASP.NET Cache DataSets for non-volatile data – Keep DataSets around for longer than a Page – Store them in session/global/cache – Expiring Caches are great for DataSets – Growing the Cache as needed with DataSets Cache DataSets for non-volatile data – Keep DataSets around for longer than a Page – Store them in session/global/cache – Expiring Caches are great for DataSets – Growing the Cache as needed with DataSets public class _default : Page { DataSet _dataSet; const MYDATASET = "MYDATASET"; void OnLoad(...) { if (Session[MYDATASET] == null) { _dataSet = new DataSet(); } else { _dataSet = (DataSet) Session[MYDATASET]; } //... Session[MYDATASET] = _dataSet; }
22
DataSets and ASP.NET (2) “What caching should I use?” – Session for user specific data E.g. User preferences, shopping cart, etc. – Application for app-level data E.g. e-commerce catalog, historical data, etc. – Cache objects for volatile data E.g. stock prices, weather data, etc. “What caching should I use?” – Session for user specific data E.g. User preferences, shopping cart, etc. – Application for app-level data E.g. e-commerce catalog, historical data, etc. – Cache objects for volatile data E.g. stock prices, weather data, etc.
23
Distributed DataSets Treat DataSets as messages – Same in Remoting DataSets as Web Services – Remote the factory that delivers DataSets – When updating, only return changes – Minimize the data across the wire with Merge Treat DataSets as messages – Same in Remoting DataSets as Web Services – Remote the factory that delivers DataSets – When updating, only return changes – Minimize the data across the wire with Merge Class DataSetFactory { // Remotely returns the DataSet public DataSet GetData() {...} // Accepts the DataSet and saves the changes, // And Returns a DataSet with a Refresh from the Database public DataSet SaveChanges(DataSet ds) {...} } DataSet newDs = factory.SaveChanges(ds.GetChanges()); ds.Merge(newDs);
24
Distributed DataSets (2) Is fine to use DataSets in Web Services – Default serialization is incorrect DiffGram Format is Platform Specific – You must make it an XML Document manually Can use GetXml() or XmlDataDocument Is fine to use DataSets in Web Services – Default serialization is incorrect DiffGram Format is Platform Specific – You must make it an XML Document manually Can use GetXml() or XmlDataDocument [WebMethod] public XmlDocument GetData() { DataSet ds = new DataSet(); // Fill the DataSet return XmlDataDocument(ds); }
25
Distributed DataSets (3) Typed DataSets are great in Web Services – Can refer to.xsd in hand-coded WSDL – While allowed, some toolkits don’t support it – No way to make ?wsdl do it (at least not yet) Typed DataSets are great in Web Services – Can refer to.xsd in hand-coded WSDL – While allowed, some toolkits don’t support it – No way to make ?wsdl do it (at least not yet) <definitions... xmlns:tds="http://yoursvr/typedds.xsd">
26
Distributed DataSets (4) Remoting may not work as expected – DataSets Remoted by Value DataSet derive from MarshalByValueComponent So always remoted by value! – Remoting DataTables/Rows does not help References to part of DataSet data transmit entire DataSet – Remoting DataSets can work Must transmit XML or subset of XML (of the DataSet) Remoting may not work as expected – DataSets Remoted by Value DataSet derive from MarshalByValueComponent So always remoted by value! – Remoting DataTables/Rows does not help References to part of DataSet data transmit entire DataSet – Remoting DataSets can work Must transmit XML or subset of XML (of the DataSet)
27
Transactions Server Transactions are usually preferable – Generally shorter, therefore better – Server Tx allows results to be returned – Server Tx are not server cursors Server Transactions are usually preferable – Generally shorter, therefore better – Server Tx allows results to be returned – Server Tx are not server cursors
28
Transactions (2) Client Transactions Have their Place – Allows a client lock of rows (connected model) – Connection must be maintained for length of Tx – Be careful when using them for locking Scalability and performance will suffer Must have recovery mechanism Client Transactions Have their Place – Allows a client lock of rows (connected model) – Connection must be maintained for length of Tx – Be careful when using them for locking Scalability and performance will suffer Must have recovery mechanism
29
Transactions (3) try { conn.Open(); using (tx = conn.BeginTransaction()) { // Get some Data using (SqlCommand cmd = conn.CreateCommand()) { cmd.CommandText = "SELECT * FROM Authors WHERE au_id = '172-32-1176'"; cmd.Transaction = tx; // Don’t forget to set the transaction into the cmd SqlDataReader rdr = cmd.ExecuteReader(); // Get the zip and close the reader rdr.Read(); string zip = rdr["zip"].ToString(); rdr.Close(); // Make a change cmd.CommandText = "UPDATE authors SET zip = ‘12345’"; cmd.ExecuteNonQuery(); // Commit the Tx tx.Commit(); } // using cmd } // using Transaction } catch { tx.Rollback(); } finally { conn.Close(); }
30
Should You Write Vendor Neutral Code? The Promise of Vendor Neutral SQL is wrong – Tuning databases too important – Standard SQL isn’t complete – Only do it if you have a compelling need You can get half the promise – Write your ADO.NET in a vendor neutral way – You may need to port the back-end code – Saves you from rewriting it all The Promise of Vendor Neutral SQL is wrong – Tuning databases too important – Standard SQL isn’t complete – Only do it if you have a compelling need You can get half the promise – Write your ADO.NET in a vendor neutral way – You may need to port the back-end code – Saves you from rewriting it all
31
Using Vendor Neutral Code Interfaces are key – IDbConnection is a great place to start – Connection Factory to return IDbConnection – Commands: IDbConnection.CreateCommand() – Readers: IDbCommand.ExecuteReader() Interfaces are key – IDbConnection is a great place to start – Connection Factory to return IDbConnection – Commands: IDbConnection.CreateCommand() – Readers: IDbCommand.ExecuteReader() IDataReader GetReader(string SQL) { // Connection String Factory IDbConnection conn = ConnectionStrings.GetConnection(); // Follow the Rest of the model IDbCommand cmd = conn.CreateCommand(); cmd.CommandText = SQL; IDataReader reader = cmd.ExecuteReader(); return reader; }
32
Using Vendor Neutral Code (2) Works with DataAdapters too (mostly) – IDbConnection is a still a great place to start – No Factory for Data Adapters unfortunately – Can use the connection to create the command Works with DataAdapters too (mostly) – IDbConnection is a still a great place to start – No Factory for Data Adapters unfortunately – Can use the connection to create the command IDbDataAdapter GetAdapter(string SQL) { // Connection String Factory IDbConnection conn = ConnectionStrings.GetConnection(); // Create the DataAdapter IDbDataAdapter adapter = new SqlDataAdapter(); // Follow the Rest of the model adapter.SelectCommand = conn.CreateCommand(); adapter.SelectCommand.CommandText = SQL; return adapter; }
33
Using Vendor Neutral Code (3) Vendor Specific Features – Can cast to get specific features of an engine – The more you do, the less vendor neutral it is – This should be the exception, not the rule Vendor Specific Features – Can cast to get specific features of an engine – The more you do, the less vendor neutral it is – This should be the exception, not the rule IDbCommand cmd = GetCommand("SELECT * FROM AUTHORS FOR XML;"); if (cmd is SqlCommand) { SqlCommand sqlCmd = (SqlCommand) cmd; XmlReader xmlReader = sqlCmd.ExecuteXmlReader(); }
34
Conclusion You can write ADO.NET badly Bad ADO.NET not nearly as toxic as bad ADO DataSets are your friend…really Relationship of DataSets and XSD is good Distributed DataSets are not that hard CommandBuilders are vaguely evil You can write ADO.NET badly Bad ADO.NET not nearly as toxic as bad ADO DataSets are your friend…really Relationship of DataSets and XSD is good Distributed DataSets are not that hard CommandBuilders are vaguely evil
35
Questions?
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.