Module 4: Buidling Datasets (Prerelease)
Module 4: Buidling Datasets (Prerelease)
Module 4: Buidling Datasets (Prerelease)
Contents Overview Lesson: Building DataSets and DataTables Lesson: Binding a DataSet to a Windows Application Control Lesson: Creating a Custom DataSet Lab 4.1: Building, Binding, Opening, and Saving DataSets Lesson: Defining Data Relationships Lesson: Modifying Data in a DataTable Lesson: Using a DataView Review Lab 4.2: Manipulating DataSets and Modifying Data 1 2 14 19 23 33 40 51 57 58
Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places, and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, places or events is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. 2001 Microsoft Corporation. All rights reserved. Microsoft, MS-DOS, Windows, Windows NT, <plus other appropriate product names or titles. The publications specialist replaces this example list with the list of trademarks provided by the copy editor. Microsoft is listed first, followed by all other Microsoft trademarks in alphabetical order. > are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners.
iii
Instructor Notes
Presentation: 60 Minutes Lab: 60 Minutes This module teaches students how to build and manage DataSets, define data relationships, modify data, and use DataViews. Because practices in this module build on files built during Lesson 1, the starter file for Lesson 2 is the solution file for Lesson 1. Lesson 3 and practices in other lessons also build upon each other. After completing this module, students will be able to:
! ! ! ! ! !
Build a DataSet and a DataTable. Bind a DataSet to a DataGrid. Create a custom DataSet by using inheritance. Define a data relationship. Modify data in a DataTable. Sort and filter a DataTable by using a DataView.
Required materials
Microsoft PowerPoint file 2389A_04.ppt Module 4, Building DataSets Lab 4.1, Building, Binding, Opening, and Saving DataSets Lab 4.2, Manipulating DataSets and Modifying Data
Preparation tasks
Read all of the materials for this module. Complete the practices and labs. Read the latest .NET Development news at http://msdn.microsoft.com/library/default.asp?url=/nhp/ Default.asp?contentid=28000519
Classroom setup
The information in this section provides setup instructions that are required to prepare the instructor computer or classroom configuration for a lab.
iv
This module focuses on defining a DataSet programmatically by using the object model. In the real world, developers are likely to spend more time using XML Schema Definitions (XSD) to define the initial schema, and use code for applications that need to be more dynamic. Using XSD to define the initial schema is covered in Module 6, NAME, in Course 2389A, Programming with ADO.NET.
Discussion Questions: Personalize the following questions to the background of the students in your class.
!
What type of application do you plan to create in which you can use DataSets? Why are DataSets and the disconnected environment suited to that type of application?
Technical Notes:
!
Show students how to create a DataSet, a DataTable, and a DataColumn in Microsoft Visual Basic and Microsoft Visual C# by clicking on the Visual Basic Example or C# Example buttons on the PowerPoint slide for this topic. In the sample for creating DataColumns, point out the use of the GetType statement in Visual Basic and the use of the typeof statement in C#. It is possible to use System.Type.GetType("System.Int32") to do the same thing in both languages if users want to be consistent, but the Microsoft Visual Studio .NET tools will use the shorthand syntax. The System.Data.DbType enumeration can be used to list all of the data types available for data columns and parameters.
Discussion Questions: Personalize the following questions to the background of the students in your class.
!
When creating ADO.NET objects, why might you want to separate the declaration statement from the instantiation statement? When would you want to combine these statements? What other exceptions might occur that you will have to control when creating DataTables and DataColumns?
Transition to Practice Exercise: Now that you have seen several examples of building DataSets and DataTables programmatically, you can now practice creating a DataSet and a DataTable. Instruct students to turn to the practice exercise at the end of this topic in the student workbook. Practice Solution: 1. In Visual Studio .NET, start a new Microsoft Windows Application project. 2. Drag a DataSet from the Data section of the Toolbox onto the form. 3. Use the Property Window to rename the DataSet. For the (Name) property, use dsNorthwind. For the DataSetName property, use Northwind. 4. Use the collection builder to add a DataTable to the Tables property of the DataSet. 5. For the (Name) property, use dtProducts. For the TableName property, use Products. 6. Use the collection builder to add three DataColumns to the Columns property of the DataTable. 7. For the (Name) property, use dcProductID. For the ColumnName property, use ProductID. 8. For the DataType property, choose System.Int32. 9. Repeat steps 7 and 8 for the ProductName and UnitPrice fields. 10. Use the code editor to manually write code to create the fourth field. Hint: Use the code that is automatically generated for the UnitPrice field as a guide; you can also copy and paste the code and then edit it. 11. Return to the form view and use the Property Window to verify that the designer recognizes the new code that you have added. If not, check that you modified the call to the AddRange method for the DataTable that adds references to the DataColumns. After the practice Questions for discussion after the practice:
! !
What lessons did you learn during the practice exercise? What did you discover as you created the DataSet, DataTable, and DataColumns?
vi
Technical Notes:
!
Visual Studio .NET Beta 2 contains a bug that prevents the interface from writing the code for constraints. Therefore, you must write the code for constraints manually. Although you can add code in the same place where the automatically generated code would be generated, using the graphical tools again will delete that code.
Transition to Practice Exercise: Using the example I just showed you as reference, you can practice programmatically creating a unique constraint for the Northwind DataSet. Instruct students to turn to the practice exercise at the end of this topic in the student workbook. Practice Solution:
!
In Visual Studio .NET, insert code in the Form1_Load event to create a unique constraint for the product name column.
Quick solution:
Me.dcProductName.Unique = True
Recommended solution:
Me.dtProducts.Constraints.Add( _ New UniqueConstraint("UC_ProductName", Me.dcProductName))
Why do you think the recommended solution is preferred over the quick solution? What lessons did you learn during the practice exercise? What did you discover as you created the unique constraint? How will you use unique constraints in your data applications?
! ! !
Technical Notes:
!
AutoIncrement columns cause problems when used with disconnected data that needs to be merged with a central database, because conflicts are likely to occur. The System.Guid and System.Data.SqlTypes.SqlGuid structures can be used as an alternative if the underlying data source uses globally unique identifiers (GUID) in the table.
Discussion Questions: Personalize the following questions to the background of the students in your class.
!
Why would AutoIncrement columns cause problems when multiple users add new rows? How does the GUID data type solve these problems? What else could you do in your applications to prevent conflicts caused by multiple users adding new rows?
! !
vii
Technical Notes:
!
Custom expressions can reference other columns in the table. They can also use summary functions such as Count and Sum that apply to all of the values in the specified column. If a DataRelation for a parent table exists, the summary functions can be grouped by parent row by using the Child object; otherwise the entire table groups them. For example:
=Sum(Child.UnitPrice) =Sum(UnitPrice)
In the first example, the UnitPrice values are grouped by the parent; in the second they are grouped by the table. Discussion Questions: Personalize the following questions to the background of the students in your class.
!
What are some other examples of situations where an expression column would be used? Could an expression column be used for concatenation of column values?
Transition to Practice Exercise: Using the syntax printed in the student workbook, you can create a custom expression for the Northwind DataSet. Instruct students to turn to the practice exercise at the end of this topic in the student workbook. Practice Solution: 1. In Visual Studio .NET, use the Property Window to add the new column to the Products table, or 2. Write code to add a fifth column with an expression, as shown in the following example:
Visual Basic Dim dcStockValue As New System.Data.DataColumn( _ "StockValue", GetType(System.Decimal)) dcStockValue.Expression = "UnitPrice*UnitsInStock" dcStockValue.ReadOnly = True
What lessons did you learn during the practice exercise? How can you use expression columns in the applications that you are building at your job?
viii
Almost all controls have a (DataBindings) property with an (Advanced) sub-property that allows any column to be bound to any control property. This is much more flexible than previous data access models that typically only allowed the Caption or Text properties to be bound.
Discussion Questions: Personalize the following questions to the background of the students in your class.
!
What is the advantage of being able to bind a DataSet to a Windows control? Give an example of using this feature in an application.
Instructor Demonstration: Demonstrate the programmatic and graphical procedures for creating a simple data-bound control. You can choose to ask students to watch you demonstrate this, or instruct them to follow the procedures on their computers as you talk through the steps.
Technical Notes:
!
Visual Studio .NET Beta 2 contains a bug that requires the DataGrid control to be bound to a DataSet through a DataView rather than directly, for reliable operation. Without an intermediate DataView, the DataGrid cannot track the current filter and sort options set for the data, as well as changes to the data.
ix
Transition to Practice Exercise: Now that you have seen how to bind a DataSet to a DataGrid both programmatically and by using the graphical tools, choose the method that you would like to use, and turn to the practice exercise at the end of this topic in the student workbook. Practice Solution: 1. Open the Visual Studio .NET development environment and the project that includes the Northwind DataSet. 2. Add five TextBox controls and a DataGrid control to the form. 3. Use the Property Window to set the DataBindings for the TextBox controls. Bind the Text property of each box to the five columns in the Products table in the Northwind DataSet. Caution Do not bind to the dtProducts variable. If you do, you will only see the first record. 4. Set the DataSource for the DataGrid to the Northwind DataSet. 5. Set the DataMember of the DataGrid to the DataTable. Notice that the TextBox controls display the same information as the currently selected row in the DataGrid. 6. Notice that you cannot have two records with the same ProductName, but that you can have two records with the same ProductID. After the practice Questions for discussion after the practice:
!
How many of you used the graphical tools to bind the DataSet to the DataGrid, and how many of you did it programmatically? What are the differences between binding a DataSet to a simple Windows control and binding a DataSet to a DataGrid?
Benefits of Inheritance
Discussion Questions: Personalize the following question to the background of the students in your class.
!
Name an example of a situation where you could use inheritance in your applications.
Instructor Demonstration: Demonstrate how to create a custom DataSet by using the Inherits statement in Visual Basic and C#. Depending on the needs of your audience, you might only need to demonstrate in one language. You can choose to ask students to watch while you demonstrate, or instruct them to follow the procedures on their computers as you talk through the steps. Transition to Practice Exercise: Now that you understand how to use the Inherits statement, you can use it to create a custom DataSet. In this practice exercise, we are going to inherit from an existing DataSet. First Ill open that DataSet by using Notepad, so that we can see what it contains. Open the DataSet file located at <install folder>\Practices\Mod04_1\catprodnone.ds. The Categories and Products tables are both defined with their structures and data in this file. Instruct students to turn to the practice exercise at the end of this topic in the student workbook to create a custom DataSet based on inheritance from the catprodnone DataSet.
xi
Practice Solution: 1. Create a Windows Application project, and add a new class called CatProdDataSet. Add the following code, changing the path to point to the correct file:
Public Class CatProdDataSet Inherits System.Data.DataSet Public Sub New() Me.ReadXml(<install folder>\Practices\Mod04_1\catprodnone.ds, XMLReadMode.ReadSchema) End Sub End Class
2. Add a DataGrid to the form. Add code to the Form1_Load event that creates an instance of the CatProdDataSet class and then binds the Categories table to the existing DataGrid. 3. Run and test the application. You should see a list of eight categories in the grid, but no way to access the products. After the practice Questions for discussion after the practice:
!
Why is there no way to access the products? What do you need to do to solve this problem? We will talk about DataSets and XML later in this course, but what do you think the ReadXml method is doing in this example?
xii
Discussion Questions: Personalize the following questions to the background of the students in your class.
!
When would you use the PrimaryKey property to define a primary key versus using the unique constraint? Describe an example of a situation where two columns need to be defined as a primary key.
Discussion Questions: Personalize the following questions to the background of the students in your class.
!
In what situations would you set the DeleteRule property to SetNull? When would you set it to SetDefault? How would you handle the exception raised when an update is made and you have set the DeleteRule property to None?
Discussion Questions: Personalize the following question to the background of the students in your class.
!
With the DeleteRule property set to None, what will happen if you try to delete a customer who has orders in the Orders table? What would we need to do in this situation?
Technical Notes:
!
It is important to differentiate between a ForeignKeyConstraint (maintains data integrity) and a DataRelation (provides navigation, grouping, and so on).
Discussion Questions: Personalize the following questions to the background of the students in your class.
!
How would a DataRelation be used with primary key and foreign key constraints? Could you use primary key and foreign key constraints without using a DataRelation? Why would you want to do this, or why not?
xiii
Discussion Questions: Personalize the following questions to the background of the students in your class.
!
You can use either the DataRelation constructor or the Add method. Why would you use one or the other? What is the difference in results between the two?
Transition to Practice Exercise: You can now choose to use either the DataRelation constructor or the Add method and practice creating constraints and a DataRelation object. Instruct students to turn to the practice exercise at the end of this topic in the student workbook. Practice Solution: In Visual Studio .NET, open the file that contains the DSCatProd DataSet, and define the following relationships for the DSCatProd DataSet on the Form1_Load event: 1. Create a PrimaryKey on the CategoryID column for the Categories table.
With ds.Tables("Categories") .Constraints.Add("PK_Categories", _ .Columns("CategoryID"), True) End With
3. Create a DataRelation and ForeignKeyConstraint between Categories and Products. (Copy and paste code to create these DataTables.)
ds.Relations.Add("FK_CategoriesProducts", _ ds.Tables("Categories").Columns("CategoryID"), _ ds.Tables("Products").Columns("CategoryID"), _ True)
Discussion Questions: Personalize the following question to the background of the students in your class.
!
How can you make use of navigating related DataTables when you begin to modify data in a DataSet?
xiv
What is the advantage of calling the Add method and passing an array of values typed as Object? What would happen if you created a new record but did not add it to the DataRowCollection?
Discussion Questions: Personalize the following question to the background of the students in your class.
!
Why do you think that navigation through records is managed by the databinding layer?
Discussion Questions: Personalize the following questions to the background of the students in your class.
! !
What is the difference between the EndEdit and CancelEdit methods? How could you programmatically use the BeginEdit and EndEdit methods to modify multiple records?
Discussion Questions: Personalize the following questions to the background of the students in your class.
!
If you used the Delete method of the DataRow object and marked the row for deletion, what would you then need to do to permanently delete the row? When would you use the Delete method of the DataRow object? What precautions might you want to take when using the Remove method of the DataRowCollection object?
! !
Discussion Questions: Personalize the following questions to the background of the students in your class.
!
How are handling DataTable events and setting the DeleteRule property on the foreign key constraint different? When would you need to set the DeleteRule property, and when would you need to handle a DataTable event? Give a business use example of why you would want to programmatically handle DataTable events in a business application.
xv
Transition to Practice Exercise: Using the example I just showed you as reference, you can practice handling the ColumnChanging DataTable event in the Northwind DataSet. Instruct students to turn to the practice exercise at the end of this topic in the student workbook. Practice Solution: In Visual Studio .NET, handle the ColumnChanging DataTable event by displaying a message box that shows the proposed new value of a modified row in the Northwind DataSet Products DataTable. 1. Declare a DataTable variable and set it to the Products table in the DataSet so that it can handle events. 2. Add the following code to the ColumnChanging event:
MessageBox.Show("From: " & e.Row.Item(e.Column) & _ ", To: " & e.ProposedValue.ToString(), _ e.Column.ColumnName)
How would you change your code to handle the ColumnChanged event? How would you change your code to handle the RowChanging event?
Discussion Questions: Personalize the following questions to the background of the students in your class.
! !
What can you deduce about the row by using these properties? Can you think of any real-world situations where you might want to use the RowState and RowVersion properties?
Discussion Questions: Personalize the following question to the background of the students in your class.
!
How will accepting or rejecting changes affect updating data in the data source?
xvi
What might be some of the differences between a DataView and a view in Microsoft SQL Server? Give another example of a situation where a DataView would be useful in your applications.
Discussion Questions: Personalize the following question to the background of the students in your class.
!
What data results would you see if you ran the code example for programmatically creating a DataView?
Discussion Questions: Personalize the following questions to the background of the students in your class.
!
Give an example of a situation where you might want to filter based on the version or state of a record? Can you sort based on the version or state of a record? Why would you use the default DataView?
Transition to Practice Exercise: Using the examples I just showed you as a reference, you can practice sorting and filtering by using a DataView. Instruct students to turn to the practice exercise at the end of this topic in the student workbook. Practice Solution:
!
Using the Visual Studio .NET development environment, build a DataView for the Products DataTable in the Northwind DataSet.
What are some of the different DataViews that you created? Did any of you sort and filter the Products DataTable by using the DataView? What kinds of filters did you create?
Overview
! ! ! ! ! !
Building DataSets and DataTables Binding a DataSet to a Windows Application Control Creating a Custom DataSet Defining Data Relationships Modifying Data in a DataTable Using a DataView
*****************************ILLEGAL FOR NON-TRAINER USE****************************** Introduction This module presents the concepts and procedures you need to create and use DataSets and related objects. DataSets allow you to store, manipulate, and modify data in a local cache while disconnected from the data source. After completing this module, you will be able to:
! ! ! ! ! ! !
Objectives
Build a DataSet and a DataTable. Bind a DataSet to a DataGrid. Create a custom DataSet by using inheritance. Define a data relationship. Modify data in a DataTable. Find and select rows in a DataTable. Sort and filter a DataTable by using a DataView.
What DataSets, DataTables, and DataColumns are How to create a DataSet, a DataTable, and a DataColumn Using constraints Using AutoIncrement columns Creating custom expressions
*****************************ILLEGAL FOR NON-TRAINER USE****************************** Introduction This lesson explains what DataSets, DataTables, and DataColumns are, how to create them programmatically, and how to include exception handling, constraints, AutoIncrement columns, and custom expressions in your Microsoft ActiveX Data Objects (ADO) .NET DataSet. After completing this lesson, you will be able to:
! ! ! ! !
Lesson objectives
Explain what DataSets, DataTables, and DataColumns are. Create a DataSet and a DataTable. Use unique constraints. Create AutoIncrement columns. Create custom expressions.
Connection
Stored Procedure
Database
Server
Data Store
*****************************ILLEGAL FOR NON-TRAINER USE****************************** Introduction In ADO .NET, DataSets, DataTables, and DataColumns allow you to represent data in a local cache and provide a relational programming model for the data regardless of its source. The ADO .NET DataSet is an in-memory cache of data and functions as a disconnected relational view of the data. The connection to the data source does not need to be active to view and manipulate data in a DataSet. This disconnected architecture enables greater scalability by using database server resources only when reading from or writing to the data source. DataSets store data similarly to the way data is stored in a relational database with a hierarchical object model of tables, rows, and columns. Additionally, you can define constraints and relationships for the data in the DataSet. DataTable objects are used to represent the tables in a DataSet. A DataTable represents one table of in-memory relational data; the data is local to the .NET application in which it resides, but it can be populated from an existing data source. A DataTable is composed of DataColumns. A DataColumn is the building block for creating the schema of a DataTable. Each DataColumn has a DataType property that determines the kind of data that each DataColumn contains. For example, you can restrict the data type to integers, strings, or decimals. Because data contained in the DataTable is typically merged back into the original data source, you must match the data types to those in the data source. DataSets and XML DataSets represent data in a relational view regardless of its source. However, data in a DataSet can be represented in XML format. The integration of DataSets with XML allows you to define the structure of a DataSet schema. For more information about the relationship between DataSets and XML, see Module 5, Using XML With ADO .NET, in Course 2389A, Programming with ADO .NET.
Definitions
To create a DataSet or manipulate data in a DataSet, you use the following classes in the System.Data namespace:
! ! ! ! ! ! !
Creating a DataSet
Dim myDataSet As DataSet myDataSet = New DataSet(CustomersDataSet)
Creating a DataTable
Dim workTable As New DataTable (Customers)
*****************************ILLEGAL FOR NON-TRAINER USE****************************** Introduction You can create DataSets and DataTables in the following ways:
! !
Programmatically By using the graphical tools in the Microsoft Visual Studio .NET development environment By using a DataAdapter and filling the DataSet with data from a relational data source By loading and persisting DataSet contents using XML
In this topic, you will learn how to create a DataSet and a DataTable programmatically, and by using the graphical tools in the Visual Studio .NET development environment. For information about filling a DataSet by using a DataAdapter, see Module 6, Building DataSets From Existing Sources, in Course 2389A, Programming with ADO .NET. For information about loading and persisting data in a DataSet by using XML, see Module 5, Using XML with ADO .NET, in Course 2389A, Programming with ADO .NET. The DataSet and DataTable constructors To create a DataSet and a DataTable programmatically, you use the DataSet constructor to initialize a new instance of the DataSet class, and use the DataTable constructor to initialize a new instance of the DataTable class. You can name the DataSet or, if the name is omitted, the name is set by default to NewDataSet. The DataSet must have a name to ensure that its XML representation always has a name for the document element, which is the highest-level element in an XML Schema definition. You can create a DataTable object by using the DataTable constructor, or by passing constructor arguments to the Add method of the DataSet objects Tables property, which is a DataTableCollection.
You can set parameters for a DataTable or a DataColumn constructor at the time that the DataTable or DataColumn is created. This is recommended because you can create the DataTable and define parameters for it by using only one line of code. After you have added a DataTable as a member of the Tables collection of one DataSet, you cannot add it to the collection of tables of any other DataSet. You can use the Clone method of a DataTable to create a new DataTable with the same structure (but no data), or you can use the Copy method to create a new DataTable with the same structure and data. Example The following example programmatically creates a DataSet named Northwind with a variable called dsNorthwind that can be used to reference it.
Dim dsNorthwind As DataSet dsNorthwind = New DataSet("Northwind")
Example
The following example creates an instance of a DataTable object and assigns it the name Customers.
Dim dtCustomers As New DataTable("Customers")
When creating most ADO .NET objects, you can separate the declaration statement from the instantiation statement (as shown in the preceding DataSet example) or combine the statements (as shown in the preceding DataTable example). Note that the DataTables created above are not yet associated with a DataSet. Creating a DataTable programmatically
The following example is the simplest way to create both a DataSet and an associated DataTable. The code creates an instance of a DataTable by adding it to the Tables collection of a newly created DataSet.
Dim dsNorthwind As New DataSet("Northwind") Dim dtCustomers As DataTable = _ dsNorthwind.Tables.Add("Customer")
You are not required to supply a value for the TableName property when you create a DataTable. You can specify the TableName property at another time, or you can leave it empty. However, when you add a table without a TableName value to a DataSet, the table is given an incremental default name of TableN, starting with Table for Table0. Creating DataColumns When you first create a DataTable, it does not have a schema. To define the tables schema, you must create and add DataColumn objects to its Columns collection. You create DataColumn objects within a table by using the DataColumn constructor or by calling the Add method of the tables Columns property. The Add method will either accept optional ColumnName, DataType, and Expression arguments and create a new DataColumn as a member of the collection, or it will accept an existing DataColumn object and add it to the collection.
Example
The following examples add a column to a DataTable using Visual Basic and Visual C#. Notice the use of the typeof statement in Visual C# and the GetType statement in Visual Basic.
' Visual Basic Dim colCustomerID As DataColumn = _ dtCustomers.Columns.Add("CustomerID", _ GetType(System.Int32)) colCustomerID.AllowDBNull = False colCustomerID.Unique = True // Visual C# DataColumn colCustomerID = dtCustomers.Columns.Add("CustomerID", typeof(Int32)); colCustomerID.AllowDBNull = false; colCustomerID.Unique = true;
Handling exceptions
You will need to programmatically control any exceptions that occur when creating a DataSet and a DataTable. DataTable names must be unique, so that an exception will be thrown when duplicate table names are used. The following example shows how to handle duplicate name exceptions programmatically.
Try dtCustomers = dsNorthwind.Tables.Add("Customers") Catch DupXcp As System.Data.DuplicateNameException MessageBox.Show("A table called Customers already exists!") ... End Try
Practice
Northwind Traders needs to build an application that includes data that is related to its products. Use the Visual Studio .NET development environment graphical tools to build a Windows Application solution. 1. Create a new Windows Application solution named CreateDataSets in the following location. <install folder>\Practices\Mod04_1\ 2. Drag and drop a DataSet control from the toolbox to the form. Name it Northwind. 3. Use the Property Window of the DataSet to build a DataTable called Products with fields called ProductID, ProductName, and UnitPrice. 4. Give each of the fields appropriate data types. 5. Open the form in Code view and find the code that was written for you by the design tools. 6. Use the automatically generated code as a guide to write some new code that creates a fourth column named UnitsInStock programmatically.
7. Add a reference to your new column to the end of the call to the AddRange method of dtProducts. This will allow the design tools to recognize your new column.
Me.dtProducts.Columns.AddRange(...
8. Return the form to Designer view and use the Property Window to see that the code you have written manually is recognized by the design tools. The solution for this practice is located at <install folder>\ Practices\Mod04_1\Lesson1\CreateDataSets\.
Practice
*****************************ILLEGAL FOR NON-TRAINER USE****************************** Introduction A relational database must enforce data integrity to ensure the quality of the data in the database. One way to maintain integrity in ADO .NET is by adding constraints to the tables within a DataSet. A constraint is an automatic rule applied to a column, or related columns, which determines what actions should take place when the value of a row is modified. There are two kinds of constraints in ADO .NET: the ForeignKeyConstraint and the UniqueConstraint. When you add a DataRelation object, which creates a relationship between two or more tables, both constraints can be created automatically. Constraints are not enforced unless the EnforceConstraints property of the DataSet is set to true. Foreign key constraints are primarily intended for use with relationships to primary key columns, and will be discussed later in this module. Unique constraints The UniqueConstraint object, which can be assigned either to a single column or to an array of columns in a DataTable, ensures that all data in the specified column(s) is unique per row. You can create a unique constraint for a single column by setting the Unique property of the column to true. You can also create a unique constraint for a column or array of columns by using the UniqueConstraint constructor and passing the UniqueConstraint object to the Add method of the tables Constraints property (which is a ConstraintCollection). You use the Add method to add existing constraint objects to the Constraints collection as well. Additionally, defining a column or columns as the primary key for a table will automatically create a unique constraint for the specified column(s). A UniqueConstraint triggers an exception when attempting to set a value in a column to a non-unique value.
10
Examples
The following examples create a UniqueConstraint object for an existing column by using two different techniques. In the first example, setting the Unique property for a column creates a constraint automatically, but it will be assigned a default name such as Constraint1. In the second example, the name of the constraint can be specified as the first parameter of the Add method.
' Visual Basic ds.Tables("Product").Columns(ProductName).Unique = True // Visual C# ds.Tables["Product"].Constraints.Add( new UniqueConstraint(UC_ProductName, ds.Tables["Product"].Columns[ProductName]));
Practice
Northwind Traders needs product names in their online catalog to be unique. 1. Open the solution you built for the previous practice, or open the solution at the following location. <install folder>\Practices\Mod04_1\Lesson1\CreateDataSets\ 2. Open the form in Designer view and double-click the form to create a handler for the Form1_Load event. 3. Write code to add a UniqueConstraint object to the Products DataTable that prevents duplicate product names. The solution for this practice is located at <install folder>\ Practices\Mod04_1\Lesson1\UsingUniqueConstraints\
11
Definition Example:
Dim myColumn As New DataColumn(ID, GetType(System.Int32)) With myColumn .AutoIncrement = True .AutoIncrementSeed = 1000 .AutoIncrementStep = 10 End With
*****************************ILLEGAL FOR NON-TRAINER USE****************************** Definition An AutoIncrement column automatically increments the value of the column for new rows added to the table. AutoIncrement columns are often used as the primary key for a table to help enforce referential integrity. The AutoIncrement property is specified on the DataColumn object. You can specify the starting value (AutoIncrementSeed property) and the amount by which the value will increment each time a new row is added (AutoIncrementStep property). AutoIncrement columns can cause problems in situations where multiple users are adding new rows, because of the likelihood of conflicts. In many situations, a better solution is to use a column with a globally unique identifier (GUID) data type; for example, the SqlTypes.SqlGuid data type. Example The following example shows how to specify the AutoIncrement property.
Dim colEmployeeID As New _ DataColumn(EmployeeID, GetType(System.Int32)) With colEmployeeID .AutoIncrement = True .AutoIncrementSeed = 1000 .AutoIncrementStep = 10 End With
12
Example:
Dim cPrice As New DataColumn(Price, GetType(System.Decimal)) Dim cTax As New DataColumn(Tax, GetType(System.Decimal)) cTax.Expression = "Price * 0.0862" Dim cTotal As New DataColumn(Total, GetType(System.Decimal)) cTotal.Expression = "Price + Tax"
Practice
*****************************ILLEGAL FOR NON-TRAINER USE****************************** Definition Custom expressions are column values derived from calculations, rather than values retrieved directly from the data source. A custom expression can be a calculation on one column or multiple columns. Syntax for a custom expression consists of standard arithmetic, Boolean, and string operators and literal values. You can reference a data value by using its column name (as you would in a SQL statement) and include aggregate functions (such as Sum, Count, Min, Max, and others). Example The Order Details table in the Northwind Traders database contains a column called UnitPrice that tracks the price of each product that is sold, and a column called Quantity that tracks the number of items that are sold. If you need to see the total cost for the purchase of a particular product, multiply the UnitPrice and the Quantity and then display the resulting value in its own column (UnitPrice*Quantity) and name the new column TotalCost. Calculated columns can also include aggregate functions such as Sum, Count, Min, Max, and other functions available with the data source. Use aggregate functions when creating an expression based on data that is related to data in another table. For example, suppose that you want to find the average unit price of products per category. To do this, you need to access two DataTables: Categories and Products. These tables are related because the CategoryID column of the Products table is the child of the Categories table. Programmatically, the new column that computes the average price of products per category would be:
Avg(Child.UnitPrice)
Aggregate functions
13
The DataColumn Expression property gets or sets the expression that is used to calculate values in a column or create an aggregate. The DataType of the column determines the return type of an expression. You can use the Expression property to:
! ! ! ! !
Create a calculated column. Create an aggregate column. Create expressions that include user-defined values. Concatenate a string. Reference parent and child tables in an expression.
Syntax
The syntax for the Expression property of the DataColumn object is:
DataColumn.Expression = Expression
Example
The following example creates three columns in a DataTable: a price column, a tax column, and a total column. The second and third columns contain expressions. The second column calculates tax by using a variable tax rate, and the third column is the result of adding the tax amount to the price.
Dim colPrice As New _ DataColumn(Price, GetType(System.Decimal)) Dim colTax As New _ DataColumn(Tax, GetType(System.Decimal)) colTax.Expression = "Price * 0.0862" Dim colTotal As New _ DataColumn(Total, GetType(System.Decimal)) colTotal.Expression = "Price + Tax"
Practice
The Northwind Traders Sales Director would like to know the value of stock being held for each product. 1. Open the solution you built for the previous practice, or open the solution at the following location. <install folder>\Practices\Mod04_1\Lesson1\UsingUniqueConstraints\ 2. Open the form in Code view and find the code that creates the columns in the Products DataTable. 3. Manually write code to add a fifth column named StockValue that should be the result of the UnitPrice column multiplied by the UnitsInStock column. 4. Use the design tools, for example the Property Window, to view the changes you have made to the Northwind DataSet. The solution for this practice is located at <install folder>\ Practices\Mod04_1\Lesson1\CreatingCustomExpressions\
14
*****************************ILLEGAL FOR NON-TRAINER USE****************************** Introduction After you have data cached in a DataSet, you must bind that DataSet to a Microsoft Windows form DataGrid control to display and manipulate or modify the data. After completing this lesson, you will be able to:
! !
Lesson objectives
15
Simple Binding and Complex Binding Binding using graphical tools and programmatically Example:
TextBox1.DataBindings.Add( _ "Text", dsNorthwind, "Products.ProductID")
*****************************ILLEGAL FOR NON-TRAINER USE****************************** Introduction Although an ADO .NET DataSet allows you to store data in a disconnected cache, the DataGrid and other Windows controls visually display data in a Windows Form and support selecting, sorting, and editing the data. In Windows Forms, you can bind any property of any control to a data source. In addition to binding the display property (such as the Text property of a TextBox control) to the data source, you can also bind other properties. For example, you may need to bind the graphic of an image control or set the size or color properties of a control based on binding to the data source. Types of data binding There are two ways to bind data to a Windows control. Simple data binding is the ability of a control to bind to a single data element, such as a value in a column in a DataSet table. This is typical for binding TextBox or Label controls, or any control that displays a single value. Complex data binding is the ability of a control to bind to more than one data element, typically more than one record in a data source. Complex data binding typically uses a DataGrid, ListBox, or ErrorProvider control. Binding a DataSet to a DataGrid control will be covered later in this module.
16
For example:
TextBox1.DataBindings.Add( _ "Text", dsNorthwind, "Products.ProductID")
17
Practice
*****************************ILLEGAL FOR NON-TRAINER USE****************************** Definition The Windows Forms DataGrid control displays data in a series of rows and columns. The simplest use of this control is when the grid is bound to a data source with a single table containing no relationships. In such a case, the data appears in simple rows and columns, as in a spreadsheet. If the DataGrid is bound to data with multiple related tables, and if navigation is enabled on the grid, the grid will display expanders in each row. An expander allows navigation from a parent table to a child table. Clicking a node displays the child table, and clicking the Back button displays the original parent table. In this way, the grid displays the hierarchical relationships between tables. If the DataSet contains a series of related tables, you can use two DataGrid controls to display the data in a relational format. Binding a DataSet to a DataGrid
18
Practice
Northwind Traders needs an application that allows the easy editing of product information. 1. Open the solution you built for the previous practice, or open the solution at the following location. <install folder>\Practices\Mod04_1\Lesson1\CreatingCustomExpressions\ 2. Open the form in Designer view. 3. Add five TextBox controls and a DataGrid control to the form. 4. Use the Property window to set the DataBindings for the TextBox controls. Bind the Text property of each box to the five columns in the Products table in the Northwind DataSet. Caution Do not bind to the dtProducts variable. If you do, you will only see the first record. 5. Set the DataSource for the DataGrid to the Northwind DataSet. 6. Set the DataMember of the DataGrid to the DataTable. 7. Run the application. 8. Enter several products into the DataGrid. Enter any values you like for the columns. Notice that the StockValue column is read only and calculated automatically. Notice that the numeric fields do not accept alphabetic values. Notice that you cannot have two records with the same ProductName, but that you can have two records with the same ProductID 9. Use your mouse to select the first product row. Notice that the TextBox controls display the same information as the currently selected row in the DataGrid. The solution for this practice is located at <install folder>\ Practices\Mod04_1\Lesson2\DataBinding\
19
*****************************ILLEGAL FOR NON-TRAINER USE****************************** Introduction By using inheritance in Visual Studio .NET, you can create a custom DataSet based on an existing DataSet. This allows for faster application development by reusing code and data. After completing this lesson, you will be able to:
! !
Lesson objectives
20
Benefits of Inheritance
! ! !
*****************************ILLEGAL FOR NON-TRAINER USE****************************** Introduction Object-oriented programming allows you to reuse code and data together through inheritance. By inheriting from existing or predefined objects, you can construct complex applications more quickly. Because new code may contain bugs, reusing tested code minimizes the probability of introducing additional bugs into the application. A common example of effective code reuse is in connection with libraries that manage data structures. Object-oriented programming is a development method in which developers create objects that cooperate with one another to form a system. Because the objects are independent, they can be reused in different applications. Definition A class inherits the members of its direct base class. Inheritance means that a class implicitly contains all members of its direct base class, except for the instance constructors, static constructors, and destructors of the base class. Inheritance is transitive. For example, if class C is derived from class B, and class B is derived from class A, then class C inherits the members declared in class B as well as the members declared in class A. A derived class extends its direct base class. A derived class can add new members to the classes that it inherits, but it cannot remove the definition of an inherited member. Example The following is an example of inheritance. The DataSet in this example is based on the MarshalByValueComponent class that provides the base implementation for components that are marshaled by value (a copy of the serialized object is passed to the DataSet).
Object MarshalByValueComponent DataSet
21
The Inherits Statement Demonstration: Creating a Custom DataSet by Using Inheritance Practice
*****************************ILLEGAL FOR NON-TRAINER USE****************************** Introduction By using inheritance to create a custom DataSet, you can save time and reuse code that already exists for other DataSets, and define a custom schema for your custom dataset that is exposed to components that use your dataset. The Inherits statement causes a class to inherit all of the non-private members of the specified class. To inherit from a class, add an Inherits statement with the name of the class that you want to use as a base class as the first statement in your derived class. The Inherits statement must be the first non-comment statement after the class statement. Demonstration
4. Add code to the New method that should run as soon as an instance of your custom class is instantiated. For example, you would write code here to create the schema for your dataset using the DataSet object model. 5. Add any additional properties, methods, fields, or other components that you want your custom DataSet to have. If necessary, override existing properties, methods, and so on.
22
4. Add code to the constructor that should run as soon as an instance of your custom class is instantiated. For example, you would write code here to create the schema for your dataset using the DataSet object model. 5. Add any additional properties, methods, fields, or other components that you want your custom DataSet to have. If necessary, override existing properties, methods, and so on. Practice The Northwind Traders IT Director would like to save money by reusing existing code. In this practice, you will create a reusable DataSet class, bind it to a DataGrid, and test the application. 1. Open the following file in Notepad and note that it contains schema and data for the Categories and Products table from the Northwind database in serialized DataSet i.e. XSD/XML format. \Program Files\MSDNTrain\2389\Practices\Mod04_1\catprodnone.ds 2. Create a new Windows Application project named CustomDataSets in the following location. <install folder>\Practices\Mod04_1\ 3. Add a new class called CatProdDataSet and add the following code:
Inherits System.Data.DataSet Public Sub New() Me.ReadXml(\Program Files\MSDNTrain\ & _ 2389\Practices\Mod04_1\catprodnone.ds, _ XmlReadMode.ReadSchema) End Sub
4. Add a DataGrid to the form. 5. Set the Dock property of the DataGrid to Fill. 6. Add code to the Form1_Load event that creates a private instance of the CatProdDataSet class named dsCatProd and then binds the Categories table to the existing DataGrid. 7. Run and test the application. You should see a list of eight categories in the grid, but note that there is no way to access the products. The solution for this practice is located at <install folder>\ Practices\Mod04_1\Lesson3\CustomDataSets\
23
Exercise 1 (Optional): Building the DataSet Test Application Exercise 2: Building the Custom DataSet Class Exercise 3: Using the DataSet in the Windows Application
*****************************ILLEGAL FOR NON-TRAINER USE****************************** Objectives After completing this lab, you will be able to:
! ! ! !
Build a DataSet that contains multiple DataTables. Bind DataSets to DataGrids. Save a DataSet as a file. Load a DataSet from an existing file.
Prerequisites
Introductory Visual Basic language skills. For example, declaring variables and writing procedures, loops, and branching statements. Introductory Windows Forms skills. For example, creating a simple form with multiple controls.
See the Visual Basic Language Features and Windows Forms Walkthroughs topics in the Visual Studio .NET documentation. Northwind Traders has an e-commerce Web site that allows customers to order products from an online catalog. Because it is a publicly available Web site, when a user first visits the site, he or she can browse catalogs and fill a shopping cart before any customer data exists in the Northwind customer database. The site automatically tracks basic information about customers and the products that they have added to their shopping carts. If a customer wishes to place an order, additional customer information must be gathered. Only during the final checkout stage is the customer and order data saved into the Northwind database. While the customer continues to shop, the data is stored temporarily in the middle tier on the Web server. The DataSet class in ADO .NET provides this capability.
24
!
2. 3.
25
4. Add an OpenFileDialog control to the form and set the following properties.
Property Name Filter Value dlgOpen DataSet files (*.ds)|*.ds|All files (*.*)|*.*
5. Add a SaveFileDialog control to the form and set the following properties.
Property Name DefaultExt Filter Value dlgSave ds DataSet files (*.ds)|*.ds|All files (*.*)|*.*
26
The Products menu item will not be used until Lab 4.2. 3. (Optional) Add menu separators where appropriate.
27
2. Set the DataSetName property to NWShoppingCart. 3. Declare local variables for the two DataTables that you will create.
Name dtCustomer dtCartItems Data type System.Data.DataTable System.Data.DataTable
28
29
30
4. Create a private procedure called SetFormCaption that contains code to display the Filename property of the dsShoppingCart object in the title bar of the form, combined with the fixed string Shopping Cart : Test WinApp. 5. Add exception handling to all procedures where appropriate.
31
2. Call the NewDataSet procedure in the Load event for Form1. 3. Call the NewDataSet procedure in the Click event for the New menu item.
32
33
How to Create a Primary Key Constraint Using Foreign Key Constraints to Restrict Actions How to Create a Foreign Key Constraint What is a DataRelation Object? How to Create a DataRelation Object How to Navigate Related DataTables
*****************************ILLEGAL FOR NON-TRAINER USE****************************** Introduction Lesson objectives Before you modify data in a DataTable, it is necessary to first define the relationships between data to ensure data integrity. After completing this lesson, you will be able to:
! ! ! !
Create a PrimaryKey constraint constructor. Create a ForeignKey constraint constructor. Create a DataRelation object. Navigate related DataTables.
34
Using the PrimaryKey property of the DataTable Using a constraint to create a primary key
workTable.Constraints.Add(PK_Customer,_ workTable.Columns(CustomerID), True)
*****************************ILLEGAL FOR NON-TRAINER USE****************************** Introduction A database table commonly has a column, or group of columns, that uniquely identifies each row in the table. This identifying column, or group of columns, is called the primary key. When you identify a single DataColumn as the primary key for a DataTable, the table automatically sets the AllowDBNull property of the column to false and the Unique property to true. For multiple-column primary keys, only the AllowDBNull property is automatically set to false. Using the PrimaryKey property of a DataTable The PrimaryKey property of a DataTable receives as its value an array of one or more DataColumn objects, as shown in the following examples.
dtCustomers.PrimaryKey = New DataColumn() _ {dtCustomers.Columns("CustomerID")}
An easier method of creating a primary key is to add a unique constraint. When doing so, the last parameter (True) can be used to indicate that a primary key should be created instead of an ordinary unique constraint.
dtCustomers.Constraints.Add( _ "PK_Customer", dtCustomers.Columns("CustomerID"), True)
35
Cascade Cascade
SetNull SetNull
Sets Sets values values in in related related rows rows to to DBNull. DBNull.
SetDefault SetDefault
Sets Sets values values in in related related rows rows to to the the DefaultValue. DefaultValue.
None None
No No action action is is taken, taken, but but an an exception exception is is raised. raised.
A foreign key constraint restricts the action performed in related tables when data in a table is either updated or deleted. For example, if a value in a row of one table is updated or deleted, and that same value is also used in one or more related tables, you can use a ForeignKeyConstraint constructor to determine what happens in the related tables. A ForeignKeyConstraint can restrict, as well as propagate, changes to related columns. Depending on the properties set for the ForeignKeyConstraint of a column, and if the EnforceConstraints property of the DataSet is true, performing certain operations on the parent row will result in an exception. For example, if the DeleteRule property of the ForeignKeyConstraint is None, a parent row cannot be deleted if it has any child rows.
In a parent-child relationship between two columns, you establish the action to be taken by setting the DeleteRule property of the foreign key constraint to one of the values in the following table.
Action Cascade SetNull SetDefault None Description Deletes or updates related rows. This is the default. Sets values in related rows to DBNull. Sets values in related rows to the DefaultValue. No action is taken, but an exception is raised
36
ForeignKeyConstraint Examples
Visual C# Example
When creating a ForeignKeyConstraint, you can pass the DeleteRule and UpdateRule values to the constructor as arguments, or you can set them as properties as in the following example (where the UpdateRule value is left as the default, Cascade). The following code shows how to create a ForeignKeyConstraint on the CustomerID column of the Orders table. The DeleteRule value is then set to prevent the deletion of any customer who has existing orders
dtCustomers = dsNorthwind.Tables("Customers") dtOrders = dsNorthwind.Tables("Orders") Dim fkcCustomersOrders As ForeignKeyConstraint = _ dtOrders.Constraints.Add( _ New ForeignKeyConstraint("FK_CustomersOrders", _ dtCustomers.Columns("CustomerID"), _ dtOrders.Columns("CustomerID"))) ' Prevent delete of customer with existing orders fkcCustomersOrders.DeleteRule = Rule.None
Example
37
Make available records related to a record with which you are working Enforce constraints for referential integrity
"
A DataRelation object defines the relationship between two tables. Typically, two tables are linked through a single field that contains the same data. For example, a table that contains address data might have a single field containing codes that represent countries/regions. A second table that contains country/region data will have a single field that contains the code that identifies the country/region; it is this code that is inserted into the corresponding field in the first table. The DataRelation object can perform the following two functions:
!
It can make available the records related to a record that you are working with. It provides child records if you are in a parent record, and a parent record if you are working with a child record. It can enforce constraints for referential integrity, such as deleting related child records when you delete a parent record.
Although a DataSet contains tables and columns in a relational structure similar to that of a database, the DataSet does not inherently include the ability to relate tables. However, you can create DataRelation objects that establish a relationship between a parent (master) and a child (detail) table based on a common key. For example, a DataSet that contains customer data might have a Customers table and an Orders table. Even if the tables contain a key in common (in this example, CustomerID), the DataSet itself does not keep track of the records in one table that relate to those in another. However, you can create a DataRelation object that references the parent and child tables (and their keys), and then use this object to work with the related tables.
38
Practice
To create a DataRelation object, you use the DataRelation constructor or the Add method of the Relations collection of a DataSet. The following example creates a DataRelation object.
dsNorthwind.Relations.Add(FK_CustomersOrders, _ dtCustomers.Columns("CustomerID"), _ dtOrders.Columns("CustomerID"), True)
Practice
The custom DataSet class you created in the previous exercise does not know about the relationship between the Categories and Products tables. 1. Open the solution you built for the previous practice, or open this solution. <install folder>\Practices\Mod04_1\Lesson3\CustomDataSets\ 2. Open the form in Code view. 3. Add code to the Form1_Load event handler that will perform the following actions. e. Create a PrimaryKey on the CategoryID column for the Categories table. f. Create a PrimaryKey on the ProductID column for the Products table. g. Create a DataRelation and ForeignKeyConstraint between Categories and Products. 4. Run and test the application. You should see a list of eight categories in the grid, and note that there is now a way to access the products: the user can click the [+] icon next to a category and drill down to see just the products for that category. The solution for this practice is located at <install folder>\ Practices\Mod04_2\Lesson1\CreateADataRelation\
39
In many application scenarios, you want to work with data from more than one table, and often data from related tables. This is called a master-detail relationship between a parent and child table. An example would be retrieving a customer record and also viewing related order information. The disconnected DataSet model allows you to work with multiple tables in your application and to define a relationship between the tables. You can then use the relationship to navigate between related records.
Definition Example
The GetChildRows method of the DataRow allows you to retrieve related rows from a child table. The following example loops through each customer and returns the order date and company name for each order in the Orders table that is related to a customer.
Dim drCustomer As DataRow Dim drOrder As DataRow For Each drCustomer In dsNorthwind.Tables(Customer).Rows For Each drOrder In drCustomer.GetChildRows( _ FK_CustomersOrders) ' process row Next Next
40
How to Insert a New Record How to Position on a Record Modifying Data in a Table How to Delete a Record How to Handle the DataTable Events What Are the RowState and RowVersion Properties? How to Accept or Reject Changes
After creating a DataTable in a DataSet, you can perform the same activities that you would perform when using a table in a database: adding, viewing, editing, and deleting data; monitoring errors and events; and querying the data. When modifying data in a DataTable, you can also verify whether the changes are accurate, and determine whether to programmatically accept or reject the changes. After completing this lesson, you will be able to:
! ! ! ! ! !
Lesson objectives
Insert a new record into a DataTable. Find records in a DataTable. Update data in DataTables. Delete a record in a DataTable. Handle the RowDeleted event. Accept or reject changes to DataTables.
41
After you create a DataTable and define its structure by using columns and constraints, you can add new rows of data to the table. To add a new row to a DataTable, you declare a new variable of the type DataRow. A new DataRow object is returned when you call the NewRow method. The DataTable then creates the DataRow object based on the structure of the table, as defined by the DataColumnCollection.
Dim drNewEmployee As DataRow = dtEmployees.NewRow()
After adding a new row to a DataTable, you can manipulate the new row by using an index or the column name.
drNewEmployee(0) = 11 drNewEmployee(1) = "Smith" drNewEmployee("EmployeeID") = 11 drNewEmployee("LastName") = "Smith"
After data is inserted into the new row, the Add method is used to add the row to the DataRowCollection.
dtEmployees.Rows.Add(drNewEmployee)
You can also call the Add method to add a new row by passing in an array of values, typed as Object.
dtEmployees.Rows.Add(New Object() {11, "Smith"})
This technique creates a new row inside the table, and sets its column values to the values in the object array. Note that values in the array are matched sequentially to the columns, based on the order in which they appear in the table.
42
In order to modify data, you first need to find the records that you want to modify. In a Windows Form application, the data-binding layer manages navigation through records in a data source. The CurrencyManager object associated with a table or view in a DataSet includes a Position property that can be used to navigate through data. Because the DataSet can contain multiple data sources, or because the controls on a form can be bound to two or more data lists, the form can have multiple currency managers.
To find a record in a Windows Form, set the Position property of the CurrencyManager object for the bound data to the record position where you would like to go.
43
Example
The following is an example of setting the Position property of the CurrencyManager object
Private myCM As CurrencyManager Private Sub BindControl(myTable As DataTable) TextBox1.DataBindings.Add("Text", myTable, "CompanyName") myCM = CType(Me.BindingContext(myTable), CurrencyManager) myCM.Position = 0 End Sub Private Sub MoveNext() If myCM.Position <> myCM.Count - 1 Then myCM.Position += 1 End If End Sub Private Sub MoveFirst() myCM.Position = 0 End Sub Private Sub MovePrevious() If myCM.Position <> 0 Then myCM.Position -= 1 End if End Sub Private Sub MoveLast() myCM.Position = myCM.Count - 1 End Sub
44
The DataRow class The BeginEdit, EndEdit, and CancelEdit methods How to modify data in a table
dt.Rows(3).BeginEdit() dt.Rows(3).Items(FirstName)=John dt.Rows(3).Items(LastName)=Smith dt.Rows(3).EndEdit()
You can modify data in a DataSet using code as well as via bound controls. The DataRow class is used to manipulate individual records. The DataRow class provides three methods for suspending and reactivating the state of the row while editing: BeginEdit, EndEdit, and CancelEdit. You call BeginEdit to suspend any events or exceptions while editing data. You use the Items collection to specify the column names of the data you want to modify and the new values. You use EndEdit to reactivate any events or exceptions, and CancelEdit to abort any changes and reactivate any events or exceptions.
The following example shows how to use the BeginEdit method, the Items collection, and the EndEdit method.
' get the third employee Dim drEmployee As DataRow = dtEmployees.Rows(3) drEmployee.BeginEdit() drEmployee("FirstName") = "John" drEmployee("LastName") = "Smith" drEmployee.EndEdit()
45
! !
You can use two methods to delete a DataRow object from a DataTable object: the Remove method of the DataRowCollection object, and the Delete method of the DataRow object. Although the Remove method deletes a DataRow from the DataRowCollection, the Delete method only marks the row for deletion. The Delete method is typically used with data in a disconnected environment.
The Remove method of the DataRowCollection takes a DataRow as an argument and removes it from the collection as shown in the following example.
Dim drEmployee As DataRow = dtEmployees.Rows(3) dtEmployees.Rows.Remove(drEmployee)
In contrast, the following example demonstrates how to call the Delete method on a DataRow to change its RowState to Deleted.
drEmployee.Delete
46
Example:
Private WithEvents dtProducts As DataTable Private Sub dtProducts_RowDeleted( _ ByVal sender As Object, _ ByVal e As System.Data.DataRowChangeEventArgs) _ Handles dtProducts.RowDeleted write code here End Sub
! !
You may need to build functionality into your application that handles events that occur on a DataTable when data is being changed or deleted. To handle DataTable events, use the WithEvents statement when declaring an object. Then, create a procedure that uses the Handles statement to associate the procedure with the event. The following example shows how to handle the RowDeleted event.
Private WithEvents dtProducts As DataTable ... Private Sub dtProducts_RowDeleted( _ ByVal sender As Object, _ ByVal e As System.Data.DataRowChangeEventArgs) _ Handles dtProducts.RowDeleted ' write code here End Sub
47
The DataTable object provides a series of events that can be processed by an application. The following table describes DataTable events.
Event ColumnChanged ColumnChanging RowChanged RowChanging RowDeleted RowDeleting Description Occurs when a value has been inserted successfully into a column. Occurs when a value has been submitted for a column. Occurs after a row in the table has been edited successfully. Occurs when a DataRow is changing. Occurs after a row in the table has been deleted. Occurs when a row in the table is marked for deletion.
Practice
The Northwind Traders Operations Manager wants more complex validation rules to apply when products are changed than can be provided by simple constraints. In this practice you will handle the ColumnChanging DataTable event. We want to see categories in the grid, and have the ability to "drill down" and see the related products, so the grid must stay bound to the Categories table. But we also want to see an event fired when a product is changed. Therefore an event handling pointer to the Products table needs to be created that responds to the Column_Changing event. 1. Open the solution you built for the previous practice, or open the solution at the following location. <install folder>\Practices\Mod04_2\Lesson1\CreateADataRelation\ 2. Open the form in Code view. 3. Declare a private DataTable variable called dtProducts with the capability of responding to events. 4. Add code to the Form1_Load event handler to point the dtProducts variable to the Products table in the Northwind DataSet. 5. Add code to handle the dtProducts ColumnChanging event by displaying a message box that shows the original value and the proposed new value of a modified product row. 6. Run and test the application by editing one of the product names. Note: you will need to drill down to find a product to edit. If you edit a category name the event will not fire! The solution for this practice is located at <install folder>\ Practices\Mod04_2\Lesson2\HandlingDataTableEvents\
48
RowState property values indicate whether and how the row has changed RowState property values: Deleted, Modified, New, and Unchanged Testing the RowVersion by calling the HasVersion method and passing a DataRowVersion as an argument
The DataRow class includes the RowState property, whose values indicate whether and how the row has changed since the DataTable was first created or loaded from the database. (RowState property values include Deleted, Modified, New, and Unchanged.) Changes made to column values in a DataRow are immediately placed in the Current state of the row. At this point the RowState is set to Modified. When modifying column values in a DataRow directly, the DataRow manages column values by using the following row versions: Current, Default, and Original. The BeginEdit, EndEdit, and CancelEdit methods utilize a fourth row version: Proposed.
You can test whether a DataRow has a particular row version by calling the HasVersion method and passing a DataRowVersion as an argument. For example, DataRow.HasVersion(DataRowVersion.Original) will return false for newly added rows. The Proposed row version exists during an edit operation that is begun by calling BeginEdit and ended with either EndEdit or CancelEdit. During the edit operation, you can apply validation logic to individual columns by evaluating the ProposedValue in the ColumnChanged event of the DataTable. The DataColumnChangeEventArgs value passed to the ColumnChanged event contains a reference to the changing column and the ProposedValue. You can modify the proposed value or trigger the edit to be canceled. The row moves out of the proposed state when the edit is completed.
49
After verifying the accuracy of changes made to data in a DataTable, you can commit the changes by using the AcceptChanges method of the DataRow, DataTable, or DataSet. This sets the Current row values to be the Original values, and sets the RowState to Unchanged. Accepting or rejecting changes deletes any RowError information and sets HasErrors to false. Accepting or rejecting changes can also affect updating data in the data source. If ForeignKeyConstraints exist on the DataTable, changes committed or rejected by using AcceptChanges and RejectChanges are propagated to child rows of the DataRow according to the ForeignKeyConstraint.AcceptRejectRule.
50
Example
The following example code checks for rows with errors, resolves the errors where applicable, and rejects the rows where the error cannot be resolved. Note that for resolved errors, the RowError value is reset to an empty string, resulting in the HasErrors property being set to false. When all of the rows with errors have been resolved or rejected, AcceptChanges is called to accept all changes for the entire DataTable.
If workTable.HasErrors Then Dim errRows() As DataRow = workTable.GetErrors() Dim I As Int32 Dim errRow As DataRow For I = 0 To errRows.Length - 1 errRow = errRows(I) If errRow.RowError = Total cannot exceed 1000. Then errRow(Total) = 1000 errRow.RowError = Else If errRow.RowState=DataRowState.Added Then I = I - 1 errRow.RejectChanges() End If Next End If workTable.AcceptChanges()
51
What Is a DataView Object? How to Define a DataView How to sort and filter a DataTable by using a DataView object
A DataView object acts similarly to the way a view acts in Microsoft SQL Server. It is an object that presents a subset of data from a DataTable. A DataView object acts like a layer on top of the DataTable, providing a filtered and sorted view of the table contents. After completing this lesson, you will be able to:
! ! !
Lesson objectives
Describe what a DataView object is. Create a DataView object. Sort and filter a DataTable by using a DataView Object.
52
Connection
Stored Procedure
DataView
Database
Screenshot
Server
Data Store
A DataView object is similar to a view in SQL Server. It is an object that presents a subset of data from a DataTable. A DataView object acts like a layer on top of the DataTable, providing a filtered and sorted view of the table contents. This capability allows you to have two controls bound to the same DataTable, but showing different versions of the data. Another benefit of the DataView object is to allow data binding on both Windows Forms and Web Forms.
Example
Suppose that a sales associate at Northwind Traders travels throughout her assigned region. While in a particular city, she may only want to see the contact information (name, company, phone number, address) for the clients in that city. You could use a DataView object to filter clients based on their city where the sales associate will be working on a particular day.
53
By using the Visual Studio .NET development environment graphical tools. Programmatically.
54
A DataView can be created independently of a DataTable and applied later to different DataTables dynamically. To apply a DataView to a DataTable, set the Table property of the DataView, as shown in the following example.
Dim dvProducts As New DataView() dvProducts.Table = dsNorthwind.Tables("Products").
55
Practice
Sorting with a DataView object allows you to set sort criteria at design time, and provides an object that you can use for data binding. You can filter and sort a DataTable by using a DataView object that you have explicitly added to a form or component. Doing this allows you to set filter and sort options at design time. Alternatively, you can use the default DataView, called DefaultView, which is available for every table in a DataSet. When you use the default view, you can specify filter and sort options programmatically.
56
To filter based on a version or state of a record, set the RowStateFilter property to a value from the DataViewRowState enumeration, such as the following:
dvProducts.RowStateFilter = DataViewRowState.CurrentRows
The following example shows how to set the DataView filter and sort order at run time by using the default DataView:
dtCustomers.DefaultView.Sort = "City"
The Northwind Traders Sales Director wants the ability to filter the products in the catalog based on customer requirements. 1. Open the solution you built for the previous practice, or open the solution at the following location. <install folder>\Practices\Mod04_2\Lesson2\HandlingDataTableEvents\ 2. Open the form in Code view. 3. Add code to the Form1_Load event handler to create a new DataView called dvExpensiveProducts based on the dtProducts variable. 4. Add code to sort the DataView on the UnitsInStock column. 5. Add code to filter the DataView so that only products costing more than $50 are displayed. 6. Run and test the application. The solution for this practice is located at <install folder>\ Practices\Mod04_2\Lesson3\SortAndFilterUsingADataView\
57
Review
! ! ! ! ! !
Building DataSets and DataTables Binding a DataSet to a Windows Application Control Creating a Custom DataSet Defining Data Relationships Modifying Data in a DataTable Using a DataView
3.
4.
5.
6.
58
Exercise 1: Creating Primary Keys and Relationships Exercise 2: Navigating Relationships Exercise 3: Editing Rows in a DataTable Exercise 4: Sorting and Filtering with DataViews
! ! !
Use a custom DataSet by using inheritance. Define a relationship. Modify data in a DataTable. Find and select rows in a DataTable. Sort and filter a DataTable by using a DataView object.
Prerequisites
59
!
2. 3.
60
The Northwind Traders database is normalized to reduce data redundancy and duplication. To extract useful information, you must join together the data in the disparate tables by using relationships before displaying it to users.
3. Add a new private procedure named AddSchema to the class. 4. After the code that creates the CartItems table, insert code to call the AddSchema procedure.
2. Wrap the code that creates the relation in an If statement that checks whether the relation already exists before attempting to create the relation. Hint: most collections provide a Contains method for this purpose.
61
62
To make its e-commerce Web site more convenient for users, Northwind Traders wants to give its customers the ability to view a running total of the order value of their shopping cart items.
63
3. Initialize the subtotal to zero. 4. Set the string variable to be the CustomerID value of the currently selected customer in the DataGrid.
Tip The CurrentRowIndex property returns the current row in a DataGrid.
5. Set the customer DataRow variable to point to the correct row in the Customer DataTable by using the CustomerID retrieved in the previous line as a criteria value for a DataRow selection filter.
Tip Use the Select method provided by the DataTable class. Caution The Select method returns an array of DataRows. Even if only one DataRow matches the select filter, you must use array syntax to retrieve an individual DataRow.
6. Write a For Each statement to loop through all of the child rows returned by a call to the GetChildRows method of the customer DataRow. 7. Inside the loop, increment the subtotal variable by the value in the Cost column of the DataRow. 8. Use a message box to show the company name of the customer and the amount they owe based on the items currently in their shopping cart.
4. Because the AddSchema method is called when a new DataSet is instantiated and when an existing DataSet file is opened, there is no additional code to write.
64
65
When browsing the Northwind Traders e-commerce Web site, a customer will want the ability to add an item to his or her shopping cart with a single click.
66
7. Try to convert the Quantity variable to an integer. If the conversion fails (for example, if the user entered an invalid value), exit the procedure. 8. Try to add the values as an array of objects using the Add method of the Rows collection of the CartItems DataTable. Catch any exceptions.
67
When browsing the Northwind Traders e-commerce Web site, a customer will want the ability to view the products in different ways; for example, products that match some criteria sorted with the cheapest products first. Customers may only want to see products that are in stock, or that have not been discontinued.
(Optional) Add menu separators where appropriate. These menu items should only be available when the products are displayed in the DataGrid. 3. Add code to handle the View menus Select event. 4. Add some code to set the Enabled property of the two menu items to have the same value as the Checked property of the Products menu item on the View menu.
68
In the following steps, you will add code to handle the Click event for these menu items.
2. Set the procedure to handle the mnuDiscontinued.Click, mnuOutOfStock.Click, and mnuProducts.Click events.
Tip Multiple procedures can handle an event. For example, we now have two procedures that handle the mnuProducts.Click event; FilterMenus and mnuProducts_Click.
3. Toggle the Checked property of the sender object, if the sender is not mnuProducts.
Tip If you are using C#, you must declare a System.Windows.Forms.MenuItem variable, cast the sender object to it, and then use that variable instead, because C# does not support late binding.
4. Declare a local DataView variable named dv and instantiate it by using the Products DataTable. 5. If the Discontinued menu item is not selected, set the RowFilter property of the DataView variable to only show rows where the Discontinued column is False. 6. If the Out Of Stock menu item is not selected, set the RowFilter property of the DataView variable to only show rows where the OutOfStock column is False. 7. If both the Discontinued and the Out Of Stock menu items are not selected, set the RowFilter property of the DataView variable to only show rows where the Discontinued column is False and the OutOfStock column is False. 8. Set the DataSource property of the DataGrid to the DataView named dv. 9. In the mnuProducts_Click procedure, delete the line of code that sets the DataSource of the DataGrid, because the FilterMenus procedure does this now.
69