This prevents parent records Flights from being deleted or having their ID col-umn values changed if related child rows Legs exist.. Not only did the first row in the Flights field have
Trang 186 Microsoft ADO NET 4 Step by Step
6 Test setting linked child fields to NULL when a parent record is deleted Set the Delete Rule field to SetNull Select the first row in the Flights field, the one with ID 759 Click
the (Flights) Delete button and confirm the delete action
7 Review the Flights and Legs fields Although the first row in the Flights field has been
removed, its child records in the Legs field remain However, their FlightID column
val-ues have been cleared and are set to NULL Those records no longer have a parent row
Defining the Update and Delete Rules in a DataRelation: Visual Basic
Note This exercise uses the “Chapter 5 VB” sample project and continues the previous exercise
in this chapter.
1 Open the source code view for the FlightInfo form Locate the RefreshConstraints
method The application lets the user alter the rules for adjusting the child table when
changes are made to the parent table The RefreshConstraints routine updates the
relevant constraint with the user’s rule choice
2 Just after the “Alter its cascade rules” comment, add the following statements:
linkConstraint.DeleteRule = CType(DeleteRule.SelectedItem, Data.Rule)
linkConstraint.UpdateRule = CType(UpdateRule.SelectedItem, Data.Rule)
3 Run the program The Update Rule and Delete Rule fields are both set to None by
default This prevents parent records (Flights) from being deleted or having their ID
col-umn values changed if related child rows (Legs) exist
4 Test cascade updates Set the Update Rule field to Cascade Select the first row in the
Flights field, the one with ID 834 Click the (Flights) Edit button Use the Edit Flight form that appears to alter the Flight ID value from 834 to another value, such as 759 Click
OK on that editor form
5 Review the Flights and Legs fields Not only did the first row in the Flights field have its
ID value changed to 759 but the FlightID values for the related rows in the Legs field
changed to 759 as well.
6 Test setting linked child fields to NULL when a parent record is deleted Set the Delete Rule field to SetNull Select the first row in the Flights field, the one with ID 759 Click
the (Flights) Delete button and confirm the delete action
7 Review the Flights and Legs fields Although the first row in the Flights field has been
removed, its child records in the Legs field remain However, their FlightID column
val-ues have been cleared and are set to NULL Those records no longer have a parent row
Trang 2Chapter 5 Bringing Related Data Together 87
Summary
This chapter demonstrated how individual DataTable instances can be joined together in an ADO.NET DataSet Each data table object includes many features that let you query and
manipulate the data in its rows By bringing distinct tables together in a data set, you gain additional features that affect multiple tables simultaneously and, if desired, automatically
The DataRelation class defines the link between columns in two different tables This class defines only the relationship; it doesn’t enforce the rules of the relationship Constraint ob-jects, specifically the UniqueConstraint and ForeignKeyConstraint derived classes, impose the
data requirements needed to ensure data integrity and data expectations between linked tables
Trang 388 Microsoft ADO NET 4 Step by Step
Chapter 5 Quick Reference
Add a table to a DataSet Define a DataSet instance.
Define a DataTable instance, adding columns and rows as needed Call the DataSet object’s Tables.Add method, passing it the instance
of the DataTable.
Link two DataTable objects in a
relation-ship
Define a DataSet instance.
Define two DataTable instances, adding columns and rows as
needed.
Determine which columns from each table will form the relationship link.
Add both tables to the DataSet using the Tables.Add method Create a DataRelation instance, passing instances of the columns to
be linked to its constructor.
Call the DataSet object’s Relations.Add method, passing it the in-stance of the DataRelation.
Enforce cascade deletes in a
parent-child relationship
Locate the DataRelation instance that defines the link relationship Set the DataRelation object’s DeleteRule to System.Data.Rule Cascade.
Locate the parent row for a child row Ensure that the tables are linked with a DataRelation.
Call the child DataRow object’s GetParentRow method, passing it the name of the DataRelation that defines the link relationship.
Locate the child rows for a parent row Ensure that the tables are linked with a DataRelation.
Call the parent DataRow object’s GetChildRow method, passing it the name of the DataRelation that defines the link relationship.
Trang 489
Chapter 6
Turning Data into Information
After completing this chapter, you will be able to:
■
■ Return a value that aggregates data from a table column
■
■ Add a column that aggregates data from a table, or from its parent or child table
■
■ Build an index-based view of a table
■
■ Generate a new table based on a projected view of the original table
After you have joined DataTable instances together in a DataSet, ADO.NET enables a few
more features that let you use those table relationships to analyze and select data These features build upon some of the single-table functions covered in earlier chapters
This chapter introduces the data-aggregation features included in the ADO.NET Framework, expressions that summarize data across multiple table rows Although not as powerful as
the aggregation features found in relational database systems, the DataTable variations still
provide quick access to multirow data summaries The chapter ends with an introduction to
the DataView class, which lets you establish row selection, filtering, and sorting standards for
a DataTable.
Note The exercises in this chapter all use the same sample project, a tool that demonstrates aggregate and data view features Although you will be able to run the application after each exercise, the expected results for the full application might not appear until you complete all exercises in the chapter.
Aggregating Data
An aggregation function returns a single calculated value from a set of related values
Averages are one type of data aggregation; they calculate a single averaged value from an input of multiple source values ADO.NET includes seven aggregation functions for use in
expression columns and other DataTable features.
■
■ Sum Calculates the total of a set of column values The column being summed must
be numeric, either integral or decimal
■
■ Avg Returns the average for a set of numbers in a column This function also requires
a numeric column
Trang 5■
■ Min Indicates the minimum value found within a set of column values Numbers, strings, dates, and other types of data that can be placed in order are all valid for the target column
■
■ Max Like Min, but returns the largest value from the available column values As with the Min function, most column types will work.
■
■ Count Simply counts the number of rows included in the aggregation You can pass any type of column to this function As long as a row includes a non-NULL value in that column, it will be counted as 1
■
■ StDev Determines the statistical standard deviation for a set of values, a common measure of variability within such a set The indicated column must be numeric
■
■ Var Calculates the statistical variance for a set of numbers, another measurement re-lated to the standard deviation Only numeric columns are supported
These seven data aggregation features appear as functions within ADO.NET expressions Expressions were introduced in the “Using Expression Columns” section of Chapter 4,
“Accessing the Right Data Values.” String expressions form the basis of custom expression
col-umns and are also used in selecting subsets of DataTable rows To aggregate data, use one of
the following function formats as the expression string:
■
■ Sum(column-name)
■
■ Avg(column-name)
■
■ Min(column-name)
■
■ Max(column-name)
■
■ Count(column-name)
■
■ StDev(column-name)
■
■ Var(column-name)
In ADO.NET, aggregates always summarize a single DataTable column Each aggregate
func-tion considers only non-NULL column values Rows that contain NULL values in the specified column are excluded from the aggregation For example, if you take the average of a table column with 10 rows, but 3 of those rows contain NULL values in the column being averaged,
the function will average only the 7 non-NULL values This is especially useful with the Count
function; it counts only the number of rows that have a non-NULL value for the passed column name If all the column values are NULL, or if there are no rows to apply to the aggregation
function, the result is NULL (System.DBNull).
Trang 6Chapter 6 Turning Data into Information 91
Generating a Single Aggregate
To calculate the aggregate of a single table column, use the DataTable object’s Compute
method Pass it an expression string that contains an aggregate function with a column-name argument
C#
DataTable employees = new DataTable("Employee");
employees.Columns.Add("ID", typeof(int));
employees.Columns.Add("Gender", typeof(string));
employees.Columns.Add("FullName", typeof(string));
employees.Columns.Add("Salary", typeof(decimal));
// - Add employee data to table, then
decimal averageSalary = (decimal)employees.Compute("Avg(Salary)", "");
Visual Basic
Dim employees As New DataTable("Employee")
employees.Columns.Add("ID", GetType(Integer))
employees.Columns.Add("Gender", GetType(string))
employees.Columns.Add("FullName", GetType(String))
employees.Columns.Add("Salary", GetType(Decimal))
' - Add employee data to table, then
Dim averageSalary As Decimal = CDec(employees.Compute("Avg(Salary)", ""))
In the preceding code, the Compute method calculates the average of the values in the Salary column The second argument to Compute is a filter that limits the rows included in the calculation It accepts a Boolean criteria expression similar to those used in the DataTable Select method call.
C#
int femalesInCompany = (int)employees.Compute("Count(ID)",
"Gender = 'F'");
Visual Basic
Dim femalesInCompany As Integer = CInt(employees.Compute("Count(ID)",
"Gender = 'F'"))
Trang 792 Microsoft ADO NET 4 Step by Step
Computing an Aggregate Value: C#
1 Open the “Chapter 6 CSharp” project from the installed samples folder The project
in-cludes three Windows.Forms classes: Switchboard, Aggregates, and DataViews.
2 Open the source code view for the Aggregates form Locate the ActCompute_Click
func-tion This routine computes an aggregate value for a single table column
3 Just after the “Build the expression” comment, add the following statement:
expression = ComputeFunction.SelectedItem.ToString() + "(" +
columnName + ")";
This code builds an expression string that combines one of the seven aggregate func-tions and a column name from the sample table
4 Just after the “Process the expression” comment, add the following code:
try
{
result = whichTable.Compute(expression, "");
}
catch (Exception ex)
{
MessageBox.Show("Could not compute the column: " + ex.Message);
return;
}
The code performs the calculation in a try block because the code that built the
ex-pression didn’t bother to verify things such as allowing only numeric columns to be
used with the Sum aggregate function The catch block will capture such problems at
runtime
5 Just after the “Display the results” comment, add the following statements:
if (DBNull.Value.Equals(result))
MessageBox.Show("NULL");
else
MessageBox.Show(result.ToString());
Some aggregates may return a NULL result depending on the contents of the column This code makes that distinction
6 Run the program When the Switchboard form appears, click Aggregate Functions
When the Aggregates form appears, use the fields to the right of the Compute label to
generate the aggregate For example, select Sum from the Aggregate Function field (the one just to the right of the Compute label), and choose Child.Population2009
from the Column Name field (the one in parentheses) Then click Compute The response of “307006550” comes from adding up all values in the child table’s
Population2009 column.
Trang 8Chapter 6 Turning Data into Information 93
Note The “Child.” prefix shown in the Column Name field is stripped out before the column
name is inserted into the expression The Compute method does not support the Parent and Child prefixes before column names.
Computing an Aggregate Value: Visual Basic
1 Open the “Chapter 6 VB” project from the installed samples folder The project includes
three Windows.Forms classes: Switchboard, Aggregates, and DataViews.
2 Open the source code view for the Aggregates form Locate the ActCompute_Click
func-tion This routine computes an aggregate value for a single table column
3 Just after the “Build the expression” comment, add the following statement:
expression = ComputeFunction.SelectedItem.ToString() & "(" &
columnName & ")"
This code builds an expression string that combines one of the seven aggregate func-tions and a column name from the sample table
4 Just after the “Process the expression” comment, add the following code:
Try
result = whichTable.Compute(expression, "")
Catch ex As Exception
MessageBox.Show("Could not compute the column: " & ex.Message)
Return
End Try
Trang 994 Microsoft ADO NET 4 Step by Step
The code performs the calculation in a Try block because the code that built the
ex-pression didn’t bother to verify things such as allowing only numeric columns to be
used with the Sum aggregate function The Catch block will capture such problems at
runtime
5 Just after the “Display the results” comment, add the following statements:
If (IsDBNull(result) = True) Then
MessageBox.Show("NULL")
Else
MessageBox.Show(result.ToString())
End If
Some aggregates may return a NULL result depending on the contents of the column This code makes that distinction
6 Run the program When the Switchboard form appears, click Aggregate Functions
When the Aggregates form appears, use the fields to the right of the Compute label to
generate the aggregate For example, select Sum from the Aggregate Function field (the one just to the right of the Compute label), and choose Child.Population2009
from the Column Name field (the one in parentheses) Then click Compute The response of “307006550” comes from adding up all values in the child table’s
Population2009 column.
Note In the example, the “Child.” prefix shown in the Column Name field is stripped out before
the column name is inserted into the expression The Compute method does not support the Parent and Child prefixes before column names.
Adding an Aggregate Column
Expression columns typically compute a value based on other columns in the same row You can also add an expression column to a table that generates an aggregate value In the absence of a filtering expression, aggregates always compute their totals using all rows in a table This is also true of aggregate expression columns When you add such a column to a table, that column will contain the same value in every row, and that value will reflect the ag-gregation of all rows in the table
Trang 10Chapter 6 Turning Data into Information 95 C#
DataTable sports = new DataTable("Sports");
sports.Columns.Add("SportName", typeof(string));
sports.Columns.Add("TeamPlayers", typeof(decimal));
sports.Columns.Add("AveragePlayers", typeof(decimal),
"Avg(TeamPlayers)");
sports.Rows.Add(new Object[] {"Baseball", 9});
sports.Rows.Add(new Object[] {"Basketball", 5});
sports.Rows.Add(new Object[] {"Cricket", 11});
MessageBox.Show((string)sports.Rows[0]["AveragePlayers"]); // Displays 8.3
MessageBox.Show((string)sports.Rows[1]["AveragePlayers"]); // Also 8.3
Visual Basic
Dim sports As New DataTable("Sports")
sports.Columns.Add("SportName", GetType(String))
sports.Columns.Add("TeamPlayers", GetType(Decimal))
sports.Columns.Add("AveragePlayers", GetType(Decimal),
"Avg(TeamPlayers)")
sports.Rows.Add({"Baseball", 9})
sports.Rows.Add({"Basketball", 5})
sports.Rows.Add({"Cricket", 11})
MessageBox.Show(CStr(sports.Rows(0)!AveragePlayers)) ' Displays 8.3
MessageBox.Show(CStr(sports.Rows(1)!AveragePlayers)) ' Also 8.3
Aggregating Data Across Related Tables
Adding aggregate functions to an expression column certainly gives you more data options,
but as a calculation method it doesn’t provide any benefit beyond the DataTable.Compute
method The real power of aggregate expression columns appears when working with
relat-ed tables By adding an aggregate function to a parent table that references the child table, you can generate summaries that are grouped by each parent row This functionality is
simi-lar in purpose to the GROUP BY clause found in the SQL language.
To apply an aggregate to a table relationship, you first add both tables to a DataSet and then add the relevant DataRelation between the linked fields After the tables are linked, you in-clude the Child keyword with the aggregate function’s column name reference.
function-name(Child.column-name)