Mastering Microsoft Visual Basic 2008 phần 9 pot

115 342 0
Mastering Microsoft Visual Basic 2008 phần 9 pot

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Petroutsos c24.tex V2 - 01/28/2008 4:48pm Page 885 Chapter 24 Advanced DataSet Operations As you know very well by now, DataSets are miniature databases that reside in the client computer’s memory. They’re made up of tables related to one another, they enforce relations, and they’re practically as close to a client-side database as you can get without installing an actual database management system at every client. However, you can’t execute SQL statements directly against the DataSet’s data. You can’t update a DataTable by issuing an UPDATE statement, and can’t add rows with an INSERT statement. You know how to iterate through the rows of a Data- Table and how to locate its related rows in other tables, and how to select rows from a DataTable with the Select method. You can iterate through the rows of a table, locate the ones that meet certain criteria, and process their columns in any way you wish: calculate aggregates on selected columns, update rows in other tables based on the values of certain columns, format text columns, even create new columns and set their values. And, of course, you know how to edit, add and delete rows, and submit the DataSet to the server. You can also process the data in the DataSet at the client with LINQ. Besides LINQ to SQL, which was discussed briefly in Chapter 17, ‘‘Querying Collections and XML with LINQ,’’ there’s another component, the LINQ to DataSet component, which enables you to query the DataSet’s data. In this chapter, I’ll focus on more-traditional querying techniques. In this chapter, you’ll learn how to do the following: ◆ Use SQL to query DataSets ◆ Add calculated columns to DataTables ◆ Compute aggregates over sets of rows Working with SQL Expressions Let’s consider a DataSet that contains the Orders and Order Details tables of the Northwind database. In Chapter 22, ‘‘Programming with ADO.NET,’’ you saw how to populate a DataSet with data from one or more database tables, how to iterate through a table’s rows, and how to traverse the related rows. In this chapter, you’ll look at some more-advanced features, such as adding custom columns to the DataSet’s DataTables and filtering a DataTable’s rows with SQL-like expressions. You can add a new column to the Order Details DataTable of the DataSet (and not the actual table in the database) and use this column to store each line’s total. You can calculate the line’s total by multiplying the quantity by the price and then subtracting the discount. Similarly, you can add a column to the Orders DataTable and store the order’s total there. To calculate an order’s total, you can sum the line totals in the Order Details DataTable over all the rows that Petroutsos c24.tex V2 - 01/28/2008 4:48pm Page 886 886 CHAPTER 24 ADVANCED DATASET OPERATIONS belong to the specific order. Writing VB code to accomplish these tasks is almost trivial; the simplest approach is to write a loop that iterates through a DataTable’s rows and calculates the aggregate. This approach, however, is neither the most elegant nor the most efficient. A better approach is to use SQL expressions to define calculated columns, as well as use SQL expressions to select rows. Do we really need all this functionality at the client? We can certainly write code to retrieve the rows needed at any time from the database. A connected application should request data from the database as needed. If you’re writing a disconnected or eventually connected application, you should be able to load a DataSet with the data you’re interested in and process it at the client. Even connected applications may benefit from the richness of the DataSet. Selecting Rows The Select method of the DataTable object allows you to select the rows that meet certain criteria. The criteria are expressed with statements similar to the WHERE clause of a SELECT statement. There are several overloaded versions of the Select method. The simplest form of the method accepts no arguments at all and returns all the rows in the DataTable to which it’s applied. Another form accepts a string argument, which is a filter expression equivalent to the WHERE clause of the SELECT statement, and returns the rows that match the specified criteria. Another form of the Select method accepts the filter expression and a second string argument that determines the order in which the rows will be returned. The last overloaded form of the method accepts the same two arguments and a third one that determines the state of the rows you want to retrieve: DataTable.Select(filter, ordering, DataRowState) The Select method returns an array of DataRow objects, which are not linked to the original rows. In other words, if you edit one of the rows in the array returned by the Select method, the matching row in the DataTable will not be modified. Even if the DataSet is strongly typed, the Select method returns an array of generic DataRow objects, not an array of the same type as the rows of the DataTable to which the Select method was applied. The following statements retrieve the ‘‘expensive’’ products from the Products DataTable: Dim expensive() As DataRow expensive = DS.Products.Select(”UnitPrice > 100”) After the execution of the Select method, the expensive array will hold the rows whose UnitPrice field is more than $100. You can also combine multiple filter expressions with the usual Boolean operators. To retrieve the expensive product with a stock over three units, use the following filter expression: ”UnitPrice > 100 AND UnitsInStock > 3” Assuming that the Orders DataTable holds the rows of the Orders table, you can retrieve the headers of the orders placed in the first three months of 1998 via the following statements: Dim Q1 1998() As DataRow Q1 1998 = DS.Orders.Select( ”OrderDate >= ’1/1/1998’ AND OrderDate <= ’3/31/1998’”) Petroutsos c24.tex V2 - 01/28/2008 4:48pm Page 887 SIMPLE CALCULATED COLUMNS 887 If you want the rows sorted by shipment date, add an argument indicating the name of the column on which the columns will be sorted and the ASC or DESC keyword: DS.Orders.Select( ”OrderDate >= ’1/1/1998’ AND OrderDate <= ’3/31/1998’”, ”DateShipped DESC”) You can select the rows that have been added to the DataSet by specifying the third argument to the Select method and two empty strings in place of the first two arguments: Dim newRows() As DataRow newRows = DS.Orders.Select(””,””, DataRowState.Added) Simple Calculated Columns Sometimes you’ll need to update a column’s value based on the values of other columns. For example, you may wish to maintain a column in the Orders DataTable that has the order’s total. For this column to be meaningful, its value should be updated every time a related row in the Order Details DataTable is modified. In the actual database, you’d do this with a trigger. However, we want to avoid adding too many triggers to our tables because they slow all data-access oper- ations, not to mention that you’ll be duplicating information. If a trigger fails to execute, the line total may not agree with the actual fields of the same row. One of the most basic rules in database design is to never duplicate information in the database. Because duplication of information some- times helps programmers in retrieving totals from the database quickly, many developers chose to break this rule and maintain totals, even though the totals can be calculated from row data. To maintain totals in a DataSet, you can add calculated columns to its DataTables. You specify a formula for the calculated column, and every time one of the columns involved in the formula changes, the calculated column’s value changes accordingly. Note that calculated columns may involve columns in the same table, or aggregates that involve columns in related tables. As you will see, calculated columns can simplify many complex reporting applications. To add a new DataColumn object to a DataTable, use the Add method of the table’s Columns collection. The Columns property of the DataTable object is a collection, and you can create new columns to the table by adding the DataColumn object to this collection. One of the overloaded forms of this method allows you to specify not only the column’s name and data type, but also its contents. The following statement adds the LineTotal column to the Order Details table and sets its value to the specified expression: DS.Tables[”Order Details”].Columns.Add( ”LineTotal”, System.Type.GetType(”System.Decimal”), ”(UnitPrice * Quantity) * (1 - Discount)”) The last argument of the Add method is an expression, which calculates the detail line’s extended price. This expression isn’t calculated when the DataSet is loaded; it’s calculated on-the-fly, every time the column is requested. You can change the values of the columns involved in the expression at will, and every time you request the value of the LineTotal column, you’ll get back the correct value. You should notice that order and invoice data isn’t changed after it’s been recorded. In other words, you shouldn’t edit thecontentsofanorder,oraninvoice,afterthe Petroutsos c24.tex V2 - 01/28/2008 4:48pm Page 888 888 CHAPTER 24 ADVANCED DATASET OPERATIONS receipt has been printed. Because order data is static, you can include the line total in your query with a statement like the following: SELECT [Order Details].*, UnitPrice * Quantity * (1 - Discount) AS LineTotal FROM [Order Details] The LineTotal column won’t change after it’s been read, even if you change the row’s quan- tity, price, or discount. If the application is going to use the DataSet for browsing only, you can populate it with the preceding SQL statement. But what if you want to run some ‘‘what if’’ scenarios? For example, you may allow users to edit the discount for selected customers and see how it affects profit. In this case, reading the line’s total from the database isn’t going to do you any good, unless you want to update the LineTotal column from within your code. If you add the same column as a calculated column to the Order Details table, you can freely edit discounts and the LineTotal column will be always up-to-date. The LineTotal calculated column is as simple as it can get because it involves the values of a few other columns in the same row. Another trivial example is the concatenation of two or more columns, as in the following example: DS.Employees.Columns.Add(”EmployeeName”, System.Type.GetType(”System.String”), ”LastName +’’+FirstName”) You can also use functions in the calculated column expressions. The following calculated column has the value Out of Stock if the AvailableQuantity column is 0 or negative, and the value Immediate Availability if the same column is positive: Ds.Tables[”Stock”].Columns.Add(”Availability”, System.Type.GetType(”System.String”), ”IIF(AvailableQuantity > 0,”& ”’Immediate Availability’, ’Out of Stock’) You can use any of the functions of T-SQL in your calculated column (string functions, date and time functions, math functions, and so on). You can also combine multiple conditions with the AND, OR,andNOT operators. Finally, you can use the IN and LIKE operators for advanced comparisons. By the way, the calculated column we just added to our DataSet doesn’t violate any database design rules, because the extra column lives in the DataSet and is used primarily for browsing purposes. We haven’t touched the database. Calculated Columns with Aggregates In addition to the simple calculated columns you explored in the preceding section, you can create calculated columns based on the values of multiple related rows. An aggregate column based on the values of related columns in other tables uses a slightly different syntax. To use aggregates, you must learn two new functions: Child() and Parent(). They both accept a relation name as an argument and retrieve the child rows or the parent row, respectively, of the current row, according to the specified relation. Petroutsos c24.tex V2 - 01/28/2008 4:48pm Page 889 SIMPLE CALCULATED COLUMNS 889 Let’s consider again a DataSet with the Orders and Order Details tables. The function Child (Orders Order Details)returns the rows of the Order Details table that belong to the current row of the Orders table: the child rows of the current order under the Orders Order Details relation. Likewise, the function Parent(Orders Order Details) returns the row of the Orders table, to which the current Order Details row belongs. The Child() function can be applied to the rows of the parent table in a relation, and the Parent() function can be applied to the rows of the child table. If the table to which either function applies has a single relation to another table, you can omit the relation’s name. If the DataSet contains only the Orders and Order Details tables, you can use the functions Child and Parent to refer the current row’s child and parent row(s) without specifying the name of the relation. To add the Items calculated column to the Orders table and store the total number of items in the order to this column, use the following statement: DS.Orders.Columns.Add(”Items”, System.Type.GetType(”System.Int32”, SUM(child.Quantity)) or the following equivalent statement: DS.Orders.Columns.Add(”Items”, System.Type.GetType(”System.Int32”, SUM(child(Orders Order Details).Quantity)) The last statement is longer but easier to read, and the same code will work even after you add new relations to the Orders table. The Items calculated column is based on an aggregate over selected rows in another table and it can simplify reporting applications that need to display totals along with each order. You can use a similar but slightly more complicated expression to calculate the total of each order: DS.Orders.Columns.Add(”OrderTotal”, System.Type.GetType(”System.Decimal”), SUM(child(Orders Order Details).UnitPrice * child(Orders Order Details).Quantity * (1 - child(Orders Order Details).Discount)”) What if we wanted to include the freight cost in the order’s total? A calculated column can either be a simple one or contain aggregates over related rows, but not both. If you need a column with the grand total of the order, you must add yet another calculated column to the Orders table and set it to the sum of the OrderTotal and Freight columns. Computing Expressions In addition to calculated columns, you can use the Compute method of the DataTable object to perform calculations that involve the current DataTable’s rows, their child rows, and their parent rows. The following statement returns an integer value, which is the number of orders placed by a specific customer: DS.Orders.Compute(”COUNT(OrderID)”, ”CustomerID = ’ALFKI’”) Petroutsos c24.tex V2 - 01/28/2008 4:48pm Page 890 890 CHAPTER 24 ADVANCED DATASET OPERATIONS Actually, the Compute method returns an object, which you must cast to the desired data type. To store the value returned by the preceding statement to an integer variable, use the following expression: Dim count As Integer count = Convert.ToInt32(DS.Orders. Compute(”COUNT(OrderID)”, ”CustomerID = ’ALFKI’”)) The Compute method returns a value; it doesn’t save the value to another column. Moreover, the Compute method allows you to limit the rows that participate in the aggregate with an expression identical to the WHERE clause of a SELECT statement. Consider again a DataSet with the Orders and Order Details DataTables. If you need the total of all orders for a specific customer, you must call the Calculate method, passing a restriction as an argument, as shown in the preceding statement. If the DataSet contained the Customers table as well, you could add a calculated column to the Customers table and store there each customer’s total for all orders. This value should be identical to the one returned by the Compute method. VB 2008 at Work: The SQL Expressions Project In this sample application, we’ll put together all the information presented so far in this chapter to build a functional application for exploring the Northwind Corporation’s sales. The applica- tion’s main form consists of a TabControl with five tab pages, which are shown in Figures 24.1 through 24.5. To use the application, you must click the Populate DataSet button at the bottom of the form. Figure 24.1 On the Orders tab of the SQL Expressions appli- cation, you can select orders based on various user-supplier criteria On the Orders tab, you can select orders based on various criteria. Note that you can’t combine the criteria, but it wouldn’t be too much work to take into consideration multiple criteria and combine them with the AND operator. On the Customer Orders tab, you can view the customers and select one to see that customer’s orders, as well as a summary of the selected customer’s orders. The Employee Orders tab is almost identical; it displays orders according to employees. On the Best Sellers tab, you can click the Top Products and Customers button to view the best-selling products and the top customers. If you click a customer name, you’ll be switched to the Customer Orders tab, where the same customer will be selected on the list and the customer’s orders will Petroutsos c24.tex V2 - 01/28/2008 4:48pm Page 891 VB 2008 AT WORK: THE SQL EXPRESSIONS PROJECT 891 appear in the ListView control at the bottom of the form. On the Order Details tab, you see the selected order’s details. No matter where you select an order by double-clicking it, its details will appear on this tab. Figure 24.2 On the Customer Orders tab, you can review cus- tomers and their orders. Figure 24.3 On the Employee Orders tab, you can review employees and their orders. Figure 24.4 On the Best Sellers tab, you can view the best-selling products and the customers with the largest sales figures. Petroutsos c24.tex V2 - 01/28/2008 4:48pm Page 892 892 CHAPTER 24 ADVANCED DATASET OPERATIONS Figure 24.5 On the Order Details tab, you can view an order’s details. The SQL Expressions project demonstrates how to write an application for navigating through related tables in all possible ways (at least, in all meaningful ways). This application is unique in that it populates a DataSet at the client and uses the data for its calculations. After the data is downloaded to the client, not a single trip to the server will be required, and as you can guess, the code uses calculated columns and the Select and Compute methods of the DataTable class. First, you must create a new DataSet, the NorthwindDataSet, with the following tables: Orders, OrderDetails,Customers,Employees,andProducts. The relations between any two of these tables will be picked up by the DataSet Designer and added to the DataSet. I was interested in the sales of the Northwind Corporation, but I’ve included the Employees, Customers, and Products tables to display actual names (product, customer, and employee names) instead of meaningless IDs. When the form is loaded, the code adds a bunch of calculated columns to the DataSet’s tables, as shown here: [Order Details].Subtotal A simple calculated column for storing each detail line’s total: If NorthwindDataSet1.Order Details.Columns (”DetailSubtotal”) Is Nothing Then NorthwindDataSet1.Order Details.Columns.Add (”DetailSubtotal”, System.Type.GetType(”System.Decimal”), ”(UnitPrice * Quantity) * (1 - Discount)”) End If Orders.OrderTotal A calculated column with aggregates for storing the order’s total: If NorthwindDataSet1.Orders.Columns(”OrderTotal”) Is Nothing Then NorthwindDataSet1.Orders.Columns.Add(”OrderTotal”, System.Type.GetType(”System.Decimal”), ”SUM(Child.DetailSubtotal)”) End If Petroutsos c24.tex V2 - 01/28/2008 4:48pm Page 893 VB 2008 AT WORK: THE SQL EXPRESSIONS PROJECT 893 Customers.CustomerTotal A calculated column with aggregates for storing the customer’s total: If NorthwindDataSet1.Customers.Columns (”CustomerTotal”) Is Nothing Then NorthwindDataSet1.Customers.Columns.Add (”CustomerTotal”, System.Type.GetType(”System.Decimal”), ”SUM(Child.OrderTotal)”) End If Products.ItemsSold A calculated column with aggregates for storing the number of items of the specific product that were sold: If NorthwindDataSet1.Products.Columns (”ItemsSold”) Is Nothing Then NorthwindDataSet1.Products.Columns.Add (”ItemsSold”, System.Type.GetType(”System.Int32”), ”SUM(Child(FK Order Details Products).Quantity)”) End If Employees.Employee A simple calculated column for storing the employee name as a single string (instead of two columns): If NorthwindDataSet1.Employees.Columns (”Employee”) Is Nothing Then NorthwindDataSet1.Employees.Columns.Add (”Employee”, System.Type.GetType(”System.String”), ”LastName + ’ ’ + FirstName”) End If Notice that the code checks to make sure that the column it’s attempting to add to the DataTable doesn’t exist already. In addition, the Quantity column’s type is changed from Integer to Decimal. This conversion is necessary because the Quantity column is used in aggregates later in the code, and the result of the aggregate is the same as the column’s type. Specifically, we’re going to calcu- late the average quantity per order with the AVG(Quantity) function of T-SQL. If the argument of the function is an integer, the result will also be an integer, even though the average is rarely an integer. The following statement changes the type of a DataColumn in the DataSet: NorthwindDataSet1.Order Details.Columns(”Quantity”).DataType = System.Type.GetType(”System.Decimal”) See the section ‘‘Aggregate Functions’ Return Values’’ a little later in this chapter for more on handling the return values of aggregate T-SQL values. Petroutsos c24.tex V2 - 01/28/2008 4:48pm Page 894 894 CHAPTER 24 ADVANCED DATASET OPERATIONS Then the code clears the DataSet and loads its tables with the following statements: NorthwindDataSet1.Clear() Me.Order DetailsTableAdapter1.Fill(NorthwindDataSet1.Order Details) Me.OrdersTableAdapter1.Fill(NorthwindDataSet1.Orders) Me.ProductsTableAdapter1.Fill(NorthwindDataSet1.Products) Me.ShippersTableAdapter1.Fill(NorthwindDataSet1.Shippers) Me.CustomersTableAdapter1.Fill(NorthwindDataSet1.Customers) Me.EmployeesTableAdapter1.Fill(NorthwindDataSet1.Employees) Now, on the Orders tab, we can look at the statements that perform the search operations. All the buttons on this tab pick up the appropriate values from the controls on the right side of the form and submit them to the Select method of the Orders DataTable. The Search By Order Date button executes the Select method shown in Listing 24.1 to retrieve the orders that were placed between the two specified dates. Listing 24.1: Retrieving Orders by Date Private Sub bttnSearchOrderByDate Click( ) Handles bttnSearchOrderByDate.Click Dim selectedRows() As DataRow selectedRows = NorthwindDataSet1.Orders.Select( ”OrderDate>=’” & dtOrderFrom.Value & ”’ AND OrderDate <=’”& dtOrderTo.Value & ”’”, ”OrderDate DESC”) ShowOrders(selectedRows) lblOrderSearchCount.Text = ”Search returned ” & selectedRows.Length.ToString & ” rows” End Sub The first argument to the Select method is an SQL expression that selects orders by data, and the second argument determines the order in which the rows of the Orders table will be returned. When the various date values are substituted, the following Select method is exe- cuted: Select(”OrderDate>=’1/1/1996’ AND OrderDate <= ’8/31/1996’”, OrderDate DESC”) TheargumentspassedtotheSelect method are identical to the WHERE and ORDER BY clauses of a SELECT statement you’d execute against the database with the Command object. The Select method, however, will act on the data in the DataSet at the client; it will not contact the server. If you need live, up-to-the-minute data, you should execute your queries directly against the database. But for many reporting tools, you can move all the relevant information to the client and work with it without additional trips to the server. The sample application shown in this section is a typical example of the type of applications that will benefit the most from working with a disconnected DataSet. [...]... more flexible and tends to suit the web programmer migrating to Visual Studio To create a web application, open Visual Studio and select the New Project option from the File menu From the New Project dialog box, expand the Visual Basic tree and select the Web option From this screen, choose ASP.NET Web Application, as shown in Figure 25.5 91 9 92 0 CHAPTER 25 BUILDING WEB APPLICATIONS Figure 25.5 Choosing... as media or databases, and even services sourced from other websites Visual Studio 2008 provides the tools to tie all this together This chapter gives an overview of the core technologies that drive the modern web application and demonstrates the basic tools available to the developer in Visual Studio 2008 I will begin with some basic concepts If you are already familiar with HTML, JavaScript, and... with each order’s total Chapter 25 Building Web Applications Developing web applications in Visual Studio 2008 has many similarities to developing traditional desktop applications You drag and drop controls onto a form and build your business logic by using your language of choice — in our case, Visual Basic 2008 However, as you will see, there are also many differences There are underlying technologies... are all used to access the 90 2 CHAPTER 25 BUILDING WEB APPLICATIONS web in the 21st century Websites, to be truly ubiquitous, are increasingly expected to be able to dynamically render their content into an appropriate format Visual Studio 2008 provides a range of tools that enable the modern developer to meet the demands of website creation from the comfort of a Visual Basic environment Database connectivity... blue is A basic page may appear as shown in Listing 25.1 Some long lines are wrapped here in print, but you can leave them all on one line in your code Listing 25.1: A Basic HTML Page Basic Page ... state is not managed correctly For the remainder of this chapter, we will discuss how to begin creating a web application in Visual Studio 2008 and examine the available web form and HTML controls Creating a Web Application Developers have two project models in Visual Studio 2008 You can use either the ASP.NET Web Application from the New Project dialog box or the New Web Site option from the File... declaration to the top of each page: Then convert the !DOCTYPE definition to the XHTML version: Finally, modify the tag to read as follows: Assuming that you have made all the correct syntax changes,... authentication before access to the rest of the site is granted In addition, personal preferences for the site can be applied to the returned pages according to the stored preferences of the registered user 90 9 91 0 CHAPTER 25 BUILDING WEB APPLICATIONS A form is created by using the . tags The commonly used attributes include the following: Name Defines a unique name for the form Action Specifies... layout classes are used inside the tags to generate the layout structure of the page Figure 25.4 Listing 25.4 running as a web page 91 5 91 6 CHAPTER 25 BUILDING WEB APPLICATIONS This is a very brief overview of CSS For more-comprehensive coverage, please refer to Mastering Integrated HTML and CSS by Virginia DeBolt There are also many online tutorials available, such as www.w3schools.com/css/ JavaScript... written in any of the NET-supported languages Prior to ASP.NET, developers working in the Microsoft platform created web applications mainly using Active Server Pages (ASP) ASPs are scripted pages that combine a variety of technologies including HTML, JavaScript, server objects, Structured Query Language (SQL), and Visual Basic Script (VBScript) ASPs are created as plain-text files and saved with the asp file . months of 199 8 via the following statements: Dim Q1 199 8() As DataRow Q1 199 8 = DS.Orders.Select( ”OrderDate >= ’1/1/ 199 8’ AND OrderDate <= ’3/31/ 199 8’”) Petroutsos c24.tex V2 - 01/28 /2008 4:48pm. NorthwindDataSet1.Customers. FindByCustomerID Petroutsos c24.tex V2 - 01/28 /2008 4:48pm Page 899 VB 2008 AT WORK: THE SQL EXPRESSIONS PROJECT 899 (custRow.CustomerID). CompanyName.ToString Dim custTotal As. list and the customer’s orders will Petroutsos c24.tex V2 - 01/28 /2008 4:48pm Page 891 VB 2008 AT WORK: THE SQL EXPRESSIONS PROJECT 891 appear in the ListView control at the bottom of the form. On

Ngày đăng: 12/08/2014, 21:20

Tài liệu cùng người dùng

Tài liệu liên quan