One of the biggest issues in working with server-side data such as SQL Server data is to minimize the amount of data that you load into an application. That's because communication with such servers is typically comparatively slow, and the servers themselves have enough processing power to quickly locate the exact data that you want. In this exercise, you'll see how you can minimize the amount of data retrieved by using a series of stored procedures with parameters.
Estimated time: 30 minutes
1. | Create a new Visual C# .NET project to use for the exercises in this chapter. |
2. | Add a new form to the project. |
3. | Place a ComboBox control (cboCustomers), a Button control (btnLoad), and a DataGrid control (dgMain) on the form. |
4. | |
5. | Using a tool such as the SQL Query Analyzer or the Visual Studio .NET IDE, create this stored procedure: CREATE PROC procCustomerList AS SELECT CustomerID, CompanyName FROM Customers ORDER BY CompanyName |
6. | Using a tool such as the SQL Query Analyzer or the Visual Studio .NET IDE, create this stored procedure: CREATE PROC procCustomerDetails @CustomerID char(5) AS SELECT * FROM Customers WHERE CustomerID = @CustomerID |
7. | |
8. | To minimize load time, the form starts by loading only the customer list into the ComboBox control. Enter this code to load the customer list in the form's Load event handler: SqlConnection cnn = new SqlConnection( "Data Source=(local);" + "Initial Catalog=Northwind;" + "Integrated Security=SSPI"); private void Exercise6_1_Load( object sender, System.EventArgs e) { // Load the customer list SqlCommand cmdCustomers = cnn.CreateCommand(); cmdCustomers.CommandType = CommandType.StoredProcedure; cmdCustomers.CommandText = "procCustomerList"; cnn.Open(); DataSet ds = new DataSet(); SqlDataAdapter da = new SqlDataAdapter(); da.SelectCommand = cmdCustomers; da.Fill(ds, "Customers"); cboCustomers.DataSource = ds.Tables["Customers"]; cboCustomers.DisplayMember = "CompanyName"; cboCustomers.ValueMember = "CustomerID"; cnn.Close(); } |
9. | When the user clicks the Load button, the other stored procedures should load only the data of interest. Enter this code to build the DataSet object and bind it to the DataGrid control in the btnLoad Click event handler: private void btnLoad_Click(object sender, System.EventArgs e) { // Create a new DataSet DataSet ds = new DataSet(); // Load only the customer of interest SqlCommand cmdCustomer = cnn.CreateCommand(); cmdCustomer.CommandType = CommandType.StoredProcedure; cmdCustomer.CommandText = "procCustomerDetails"; cmdCustomer.Parameters.Add( new SqlParameter( "@CustomerID", SqlDbType.Text, 5)); cmdCustomer.Parameters["@CustomerID"]. Value = cboCustomers.SelectedValue; SqlDataAdapter daCustomer = new SqlDataAdapter(); daCustomer.SelectCommand = cmdCustomer; daCustomer.Fill(ds, "Customers"); // Load the orders for this customer SqlCommand cmdOrders = cnn.CreateCommand(); cmdOrders.CommandType = CommandType.StoredProcedure; cmdOrders.CommandText = "procOrdersForCustomer"; cmdOrders.Parameters.Add( new SqlParameter( "@CustomerID", SqlDbType.Text, 5)); cmdOrders.Parameters["@CustomerID"]. Value = cboCustomers.SelectedValue; SqlDataAdapter daOrders = new SqlDataAdapter(); daOrders.SelectCommand = cmdOrders; daOrders.Fill(ds, "Orders"); // Relate the two DataTables DataRelation relCustOrder = ds.Relations.Add( "CustOrder", ds.Tables["Customers"]. Columns["CustomerID"], ds.Tables["Orders"]. Columns["CustomerID"]); // Bind the data to the user interface dgMain.DataSource = ds; dgMain.DataMember = "Customers"; } |
10. | Insert the Main() method to launch the form. Set the form as the startup form for the project. |
11. | Run the project. Select a customer from the list in the combo box and then press the Load button. The form displays only the information for that customer. Click on the + sign next to the customer to see the order information, as shown in Figure 6.29. Figure 6.29. You can use parameterized stored procedures to minimize the amount of data that you need to load into an application. |
The DataSet object has facilities for saving data as XML. But sometimes file size is more important than the readability that XML brings to the table. In this exercise, you'll retrieve data from a database and then use the BinaryWriter class to write the data out as a compact disc file.
Estimated time: 20 minutes
You've seen how to load data from more than one table into the same DataSet object and how to update a database with changes that were made to a DataSet object. In this exercise, you'll combine the two and write code to update multiple tables that are contained in a single DataSet object.
Estimated time: 25 minutes
Popular RDBMS software uses transactions to maintain database integrity. A transaction is a single unit of work. If a transaction is successful, all the data modifications made during the transaction are committed and become permanent parts of the database.
If a transaction encounters errors or is invalid, then it must be canceled or rolled back; in that case, all the data modifications in that transaction are erased.
In this exercise, I use the SqlTransaction class, which represents a T-SQL transaction on a SQL Server database. A transaction is explicitly started by using the SqlConnection.BeginTransaction() method. The newly created SqlTransaction object is then assigned to the Transaction property of the current command object. If the changes need to be committed to the database, you use SqlTransaction.Commit() method, whereas if the changes to the database need to be rolled back, you use the SqlTransaction.RollBack() method. Both the Commit() and RollBack() methods end the current transaction.
EXAM TIP
Using Transactions with ADO.NET You can create a SqlTransaction object by calling the BeginTransaction() method on the SqlConnection object. After you have the SqlTransaction object available, all subsequent operations associated with the transaction, such as Commit() and RollBack(), are performed on the SqlTransaction object instead of the SqlConnection object.
Estimated time: 25 minutes
1: | Describe the difference between an ad hoc query and a stored procedure. |
2: | List and describe the four basic T-SQL statements. |
3: | Name four ways that you can execute SQL statements. |
4: | In a T-SQL SELECT statement, what is the difference between the WHERE clause and the HAVING clause? |
5: | What is the purpose of the @@IDENTITY variable? |
6: | What is a stream? What is a backing store? |
7: | How should you decide between using a StreamReader object and using a BinaryReader object? |
8: | Describe the difference between the data provider objects and the DataSet objects. |
9: | Which ADO.NET object do you use to execute a stored procedure? |
10: | Which ADO.NET object transfers data between the database and the data model? |
11: | What are the advantages of strongly typed DataSet objects? |
12: | Which XML object can you synchronize with a DataSet object? |
13: | Name and describe the two main types of concurrency control that you can implement in .NET. |
1: | Your SQL Server database contains a table, Sales, with these columns:
SalesID (int, identity) StoreNumber (int) Sales (int) You want to see a list of the stores, together with their total sales. The list should be filtered to include only stores whose total sales are more than 10. Which SQL statement should you use?
|
2: | Your SQL Server database contains a table, Sales, with these columns:
SalesID (int, identity) StoreNumber (int) Sales (int) You want to see a list of the stores, together with their total sales. The list should be filtered to include only rows from the table where the sales are more than 10. Which SQL statement should you use?
|
3: | Your SQL Server database contains a table, Experiments, with the following columns:
ExperimentID (int, identity) ExperimentType (char(1)) ExperimentDate (datetime) You want to delete all rows from the table where the ExperimentType value is either A or C. You do not want to delete any other rows. Which SQL statement should you use?
|
4: | Your SQL Server database contains a table, Sales, with these columns:
SalesID (int, identity) StoreNumber (int) Sales (int) You want to create a stored procedure that accepts as inputs the store number and sales, inserts a new row in the table with this information, and returns the new identity value. Which SQL statement should you use?
|
5: | Your application has two FileStream objects. The fsIn object is open for reading, and the fsOut object is open for writing. Which code snippet would copy the contents of fsIn to fsOut using a 2KB buffer?
|
6: | Your application includes 15 double-precision floating-point numbers that you want to write out to a disk file. You'd like to minimize the size of the disk file. Which object should you use to write the file?
|
7: | Your application needs to return the total number of customers in a database. What is the fastest way to do this?
|
8: | Your application needs to retrieve a list of customer balances from a SQL Server database. The application should move through the list once, processing each balance in turn. The application does not need to write to the database. Which object should you use to hold the list in the data model?
|
9: | Your SQL Server database contains customer and order information. The Orders table includes a foreign key that refers to the Customers table. You have loaded the Customers and Orders tables into a single DataSet object through two separate SqlDataAdapter objects. The DataSet object is bound to a DataGrid control on the application's user interface. When you run the application, only customer information appears in the DataGrid control. You have verified that there are orders in the database. What is the most likely cause of this problem?
|
10: | Your application uses a SqlDataReader object to retrieve information about customer balances. When you find a past-due balance, you want to write a new entry to a billing table by executing a stored procedure in the same database. You have used a SqlCommand object to represent the stored procedure. Calling the ExecuteNonQuery() method of the SqlCommand object is causing an error. What is the most likely cause of this error?
|
11: | Your application allows the user to edit product data on a DataGrid control. The DataGrid control is bound to a DataSet object. The DataSet object is filled through a SqlDataAdapter object. The InsertCommand, UpdateCommand, and DeleteCommand properties of the SqlDataAdapter object are set to SqlCommand objects, and you have tested the SQL in those SqlCommand objects.
When users exit the application, none of their changes are saved to the database, and they do not receive any errors. What could be the problem?
|
12: | Your application includes a DataSet object that contains a DataTable object named Suppliers. This DataTable object contains all rows from the Suppliers table in your database. You want to bind an object to a DataGrid control on a form such that the DataGrid control displays only the suppliers from Pennsylvania. What should you do?
|
13: | You allow users to edit product information on a DataGrid control that is bound to a DataSet object. When the user clicks the Update button on the form, you call the SqlDataAdapter.Update() method to cause the changes from the DataSet object to persist to the underlying database.
Users report that new records and updated rows are saved properly but that deleted rows are reappearing the next time they run the application. What could be the problem?
|
14: | Your application recursively calls the FirstChild() and NextChild() methods of XmlNode objects to visit every node in an XML file. When you find a node that includes customer name information, you store the information. The application is not returning all the customer names from the file. What could be the problem?
|
15: | Your application reads an XML file from disk into an XmlDocument object, and then it modifies some of the nodes in the document. Which object should you use to write the modified XmlDocument object back to disk?
|
16: | You have designed an application to use optimistic concurrency control. Alice and Bob each retrieve the Products table to the application at 8:00 a.m. The initial price of a widget is $3. At 8:05 a.m., Alice changes the price of a widget to $4 and saves her changes to the database. At 8:10 a.m., Bob changes the price of a widget to $5 and saves his changes to the database. What would be the price of a widget in the database at 8:11 a.m. if no one made any other changes?
|
A1: | An ad hoc query consists of SQL statements that are sent to the server. A stored procedure consists of SQL statements that are permanently stored on the server. |
A2: | The SELECT statement retrieves data, the UPDATE statement updates existing data, the INSERT statement adds new data, and the DELETE statement deletes data. |
A3: | Using the Visual Studio .NET IDE, through osql, through the SQL Query Analyzer, or with your own home-grown solutions. |
A4: | The WHERE clause restricts the rows that are used as input to an aggregate. The HAVING clause restricts the rows that are output from an aggregate. |
A5: | The @@IDENTITY variable returns the last identity value to have been assigned to a table. |
A6: | A stream is a file viewed as a list of bytes. A backing store is a place where data can be stored. |
A7: | The StreamReader object is most useful when you're dealing with a line-oriented text file. The BinaryWriter object is most useful when you're working with a file in a particular format. |
A8: | There are multiple sets of platform- and product-specific data provider objects. A single set of DataSet objects holds abstract data that's not directly associated with any database. |
A9: | The SqlCommand object can be used to execute a stored procedure. |
A10: | The SqlDataAdapter object is the pipeline between the data model and the DataSet object. |
A11: | Strongly typed DataSet objects give you the benefit of IntelliSense at design time. They also provide earlier data binding than late data binding by ordinary DataSet objects. |
A12: | The XmlDataDocument object can be synchronized with a DataSet object. |
A13: | With optimistic concurrency control, an update to a row succeeds only if no one else has changed that row after it is loaded into the DataSet object. With “last one wins” concurrency control, an update to a row always succeeds, whether another user has edited the row or not (as long as the row still exists). |
A1: | C. The GROUP BY clause is required to obtain aggregate numbers. The HAVING clause filters the results after the aggregation has been performed. The answers that contain the WHERE clause are incorrect because WHERE filters the input to the aggregations. For more information, see the section “The SELECT Statement” in this chapter. |
A2: | B. The GROUP BY clause is required to obtain aggregate numbers. The WHERE clause filters rows before aggregating them. The answers that contain the HAVING clause are incorrect because HAVING filters the results after aggregation.For more information, see the section “The SELECT Statement” in this chapter. |
A3: | A. Answer B would also delete rows with an ExperimentType value of B. Answer C would take the OR of A and C before evaluating the LIKE clause. DELETE * is not valid T-SQL syntax. For more information, see the section “The DELETE Statement” in this chapter. |
A4: | D. Answer A does not indicate that @SalesID is an output parameter. Answers B and C attempt to insert values into the identity column, rather than let SQL Server assign the new value. For more information, see the section “Using Stored Procedures” in this chapter. |
A5: | C. The Read() method returns the number of bytes read, so Answers B and D fail when there is 1 byte in the file. The Read() method reads to a byte array, so Answers A and B fail because the buffer has the wrong data type. For more information, see the section “Using the FileStream Class” in this chapter. |
A6: | C. The BinaryWriter object provides a compact format for data storage on disk, as long as you don't need the data to be human-readable. All the other objects store the data as ASCII text, which takes more space. For more information, see the section “Using the BinaryReader and BinaryWriter Classes” in this chapter. |
A7: | C. Stored procedures execute faster than the corresponding ad hoc SQL statements because stored procedures are stored in the database in compiled form. Using the ExecuteScalar() method is faster than filling a DataSet object for returning a single value. For more information, see the section “The SqlCommand and SqlParameter Objects” in this chapter. |
A8: | B. The SqlDataReader object gives you a fast, forward-only, read-only view of the data. It is ideal for processing all rows once, without extra overhead. For more information, see the section “The SqlDataReader Object” in this chapter. |
A9: | B. Even though the two tables are related in the database, you must still tell the DataSet object what the relationship is by creating a DataRelation object. For more information, see the section “Using DataSet Objects” in this chapter. |
A10: | D. While a SqlDataReader object is open, you cannot execute other commands on the SqlConnection object that the SqlDataReader object is using. For more information, see the section “The DataProviders Objects” in this chapter. |
A11: | A. If you do not call the SqlDataAdapter. Update() method, all changes to the data model are lost. Answer B would return an error to the users. Answer C is incorrect because a bound DataSet object automatically reflects changes to the DataGrid control. Answer D is incorrect because DataSet objects are designed to be edited. For more information, see the section “Using DataSet Objects” in this chapter. |
A12: | D. Answers A and C do not give you objects that can be bound to the DataGrid control. Answer B works, but retrieving the data from the database a second time is slower than filtering it from the existing DataTable object. For more information, see the section “Finding and Sorting Data in DataSet Objects” in this chapter. |
A13: | D. If Answers A or C were the case, none of the changes would be saved. Answer B is simply incorrect. For more information, see the section “Editing Data with ADO.NET” in this chapter. |
A14: | C. By default, XML attributes do not appear as part of the XmlNodes that is traversed by the FirstChild and NextSibling properties. If Answers A or B were the case, you would not be able to load the file into an XmlDocument object. Answer D is incorrect because HasChildNodes is automatically set by the .NET Framework. For more information, see the section “Using XML Data” in this chapter. |
A15: | A. The XmlTextWriter object is designed to write XML files, preserving the proper XML structure. For more information, see the section “Using XML Data” in this chapter. |
A16: | B. With optimistic concurrency control, Bob's change is not written to the database. For more information, see the section “Handling Multiuser Errors” in this chapter. |
1. SQL Server Books Online, “Transact-SQL Reference”
2. Visual Studio .NET Combined Help Collection:
• “Overview of ADO.NET”
• “XML in Visual Studio”
3. .NET Framework SDK documentation:
• “Accessing Data with ADO.NET”
• “Basic File I/O”
4. Bob Beauchemin . Essential ADO.NET. Addison-Wesley, 2002.
5. David Sceppa . Microsoft ADO.NET (Core Reference). Microsoft Press, 2002.
6. Kalen Delaney . Inside SQL Server 2000. Microsoft Press, 2000.
7. .NET Data Access Architecture Guide. msdn.microsoft.com/library/en-us/dnbda/html/daag.asp.
8. Designing Data Tier Components and Passing Data Through Tiers. www.microsoft.com/downloads/release.asp?ReleaseID=44269.
9. Microsoft Support Webcast: XML Integration in ADO.NET. support.microsoft.com/servicedesks/webcasts/wc022202/wcblurb022202.asp.
10. Microsoft Support Webcast: Microsoft ADO.NET: Programming ADO.NET Datasets. support.microsoft.com/servicedesks/webcasts/wc041202/wcblurb041202.asp.
11. Microsoft Support Webcast: Programming XML in the Microsoft .NET Framework Part I. support.microsoft.com/servicedesks/webcasts/wc121801/wcblurb121801.asp.
12. Microsoft Support Webcast: Programming XML in the Microsoft .NET Framework Part II. support.microsoft.com/servicedesks/webcasts/wc010302/wcblurb010302.asp.
13. Microsoft Support WebCast: Accessing Data with Microsoft Visual C# Applications. support.microsoft.com/servicedesks/webcasts/wc092101/wcblurb092101.asp.
14. Microsoft Support WebCast: ADO.NET. support.microsoft.com/servicedesks/webcasts/wc081401/wcblurb081401.asp.
15. The .NET Show: ADO.NET. msdn.microsoft.com/theshow/Episode017.
3.134.88.228