OdbcCommand dataCommand = new OdbcCommand(); dataCommand.Connection = dataConnection; // Build command string StringBuilder commandText = new StringBuilder("DELETE FROM [Orders Details] WHERE OrdersID = "); commandText.Append(orderID); commandText.Append(" and ProductID = "); commandText.Append(productID); dataCommand.CommandText = commandText.ToString(); int rows = dataCommand.ExecuteNonQuery(); // Make sure that the DELETE worked Assert.AreEqual(1, rows, "Unexpected Orders Details row count, gasp!"); dataConnection.Close(); lineItem = null; } catch(Exception e) { Assert.Fail("Orders Details database error: " + e.Message); } } } } Listing 15-10. OrderDetailData.cs File #region Using derectives using System; using System.Collections.Generic; using System.Data using System.Data.Odbc; using System.Text; using BusinessLayer; #endregion namespace DataLayer { public class OrderDetailData { public OrderDetailData() { } CHAPTER 15 ■ SECOND ITERATION 253 4800ch15.qrk 5/23/06 8:20 PM Page 253 public static int InsertLineItem(int orderID, LineItem lineItem) { int rows = -1; try { Product product = lineItem.Item; OdbcConnection dataConnection = new OdbcConnection(); dataConnection.ConnectionString = DataUtilities.ConnectionString; dataConnection.Open(); OdbcCommand dataCommand = new OdbcCommand(); dataCommand.Connection = dataConnection; // Build command string StringBuilder commandText = new StringBuilder("INSERT INTO [Orders Details] ("); commandText.Append("OrdersID, "); commandText.Append("ProductID, "); commandText.Append("UnitPrice, "); commandText.Append("Quantity, "); commandText.Append("Discount) VALUES ("); commandText.Append(orderID); commandText.Append(", "); commandText.Append(product.ProductID); commandText.Append(", "); commandText.Append(product.Price); commandText.Append(", "); commandText.Append(lineItem.Quantity); commandText.Append(", "); commandText.Append(0); commandText.Append(")"); dataCommand.CommandText = commandText.ToString(); rows = dataCommand.ExecuteNonQuery(); dataConnection.Close(); } catch(Exception e) { Console.WriteLine(e.Message); } CHAPTER 15 ■ SECOND ITERATION254 4800ch15.qrk 5/23/06 8:20 PM Page 254 return rows } } } Listing 15-11. OrderDetail.cs File #region Using directives using System; using System.Collections.Generic; using System.Text; #end region namespace BusinessLayer { public class OrderDetail { private int orderID; private int productID; private decimal unitPrice; private int quantityOrdered; private float discount; public OrderDetail() { } public OrderDetail(int orderID, int productID, decimal unitPrice, int quantityOrdered, float discount) { this.orderID = orderID; this.productID = productID; this.unitPrice = unitPrice; this.quantityOrdered = quantityOrdered; this.discount = discount; } CHAPTER 15 ■ SECOND ITERATION 255 4800ch15.qrk 5/23/06 8:20 PM Page 255 public int OrderID { get { return this.orderID; } set { this.orderID = value; } } public int ProductID { get { return this.productID; } set { this.productID = value; } } public decimal UnitPrice { get { return this.unitPrice; } set { this.unitPrice = value; } } public int QuantityOrdered { get { return this.quantityOrdered; } set { this.quantityOrdered = value; } } CHAPTER 15 ■ SECOND ITERATION256 4800ch15.qrk 5/23/06 8:20 PM Page 256 public float Discount { get { return this.discount; } set { this.discount = value; } } } } This concludes the test, data, and business classes. You should be able to successfully build and test the entire solution. Once you have resolved any build or test issues, you are ready to move on to the web layer. Add Button to Check Out the Shopping Cart Contents Task The first web layer task is to add a button to the DisplayShoppingCart.aspx so that users can start the process of placing their order. Listing 15-12 shows the updated DisplayShoppingCart.aspx code. Listing 15-12. DisplayShoppingCart.aspx File <%@ Import Namespace="BusinessLayer" %> <%@ Import Namespace="DataLayer" %> <%@ Import Namespace="System.Collections" %> <%@ Register TagPrefix="Categories" TagName="LeftNav" Src="Categories.ascx" %> <%@ Register TagPrefix="TopNav" TagName="TopNav" Src="TopNav.ascx" %> <%@ Page language="c#" CodeFile="DisplayShoppingCart.aspx.cs" AutoEventWireup="false" Inherits="NorthwindWeb.DisplayShoppingCart" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3c.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3c.org/1999/xhtml"> <head> <title>Display Shopping Cart</title> </head> <body> <table id="Table1" cellspacing="1" cellpadding="1" width="100%" border="0"> <tr> <td colspan="2" style="height: 43px"> <TopNav:TopNav id="topnav" runat="server" /> </td> </tr> CHAPTER 15 ■ SECOND ITERATION 257 4800ch15.qrk 5/23/06 8:20 PM Page 257 <tr> <td width="20%" valign="top" align="left"> <Categories:LeftNav id="leftnav" runat="server" /> </td> <td valign="top" align="left"> <table width="100%"> <tr> <th align="left"> Product</th> <th align="left"> Price</th> <th align="left"> Available</th> <th align="left"> Quantity</th> <th> </th> </tr> <% while (cartEnumerator.MoveNext()) { %> <form action="DisplayShoppingCart.aspx" id="UpdateContents" method="post"> <tr> <% lineItem = (LineItem)cartEnumerator.Value; Product product = lineItem.Item; Response.Write("<td>" + product.ProductName + "</td><td>" + product.Price.ToString("C") + "</td><td>" + product.Quantity.ToString() + "</td>"); Response.Write("<input type=\"hidden\" name=\"availableQty\""+ "value=\"" + product.Quantity + "\">"); Response.Write("<input type=\"hidden\" name=\"productID\""+ "value=\"" + product.ProductID + "\">"); %> <td> <input type="text" size="2" name="quantity" value="<%=lineItem.Quantity%>"> <% Response.Write(lineItem.Message); lineItem.Message = ""; %> </td> CHAPTER 15 ■ SECOND ITERATION258 4800ch15.qrk 5/23/06 8:20 PM Page 258 <td> <input type="submit" value="Update Quantity"> </td> </tr> </form> <% } %> </table> </td> </tr> <tr> <td colspan="5" align="center"> <form action="CheckoutConfirmation.aspx" id="CheckoutConfirmation" method="post"> <input type="submit" value="Checkout" /> </form> </td> </tr> </table> </body> </html> This will take the user to the CheckOutConfirmation.aspx page. Create Checkout Confirmation Page Task Now that the DisplayShoppingCart.aspx page allows the user to check out, you need to build the confirmation page called CheckoutConfirmation.aspx, as shown in Listing 15-13. Listing 15-13. CheckoutConfirmation.aspx File <%@ Import Namespace="BusinessLayer" %> <%@ Import Namespace="DataLayer" %> <%@ Import Namespace="System.Collections" %> <%@ Register TagPrefix="Categories" TagName="LeftNav" Src="Categories.ascx" %> <%@ Register TagPrefix="TopNav" TagName="TopNav" Src="TopNav.ascx" %> <%@ Page Language="c#" CodeFile="CheckoutConfirmation.aspx.cs" AutoEventWireup="true" Inherits="CheckoutConfirmation" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3c.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3c.org/1999/xhtml"> <head> <title>Checkout Confirmation</title> </head> CHAPTER 15 ■ SECOND ITERATION 259 4800ch15.qrk 5/23/06 8:20 PM Page 259 <body> <table id="Table1" cellspacing="1" cellpadding="1" width="100%" border="0"> <tr> <td colspan="2" style="height: 43px"> <TopNav:TopNav id="topnav" runat="server" /> </td> </tr> <tr> <td width="20%" valign="top" align="left"> <Categories:LeftNav id="leftnav" runat="server" /> </td> <td valign="top" align="left"> </td> </tr> </table> </body> </html> This creates a basic page with the top and left navigation pieces. Now when users click the Checkout button on the DisplayShoppingCart.aspx page, they go here. But you aren’t display- ing anything yet. Let’s move on to the next task. Display Shopping Cart Contents in Checkout Confirmation Page Task You will need to retrieve the shopping cart that you have been building and display its con- tents. To do that, enhance CheckoutConfirmation.aspx as shown in Listing 15-14. Listing 15-14. Modified CheckoutConfirmation.aspx to Show Shopping Cart Contents <%@ Import Namespace="BusinessLayer" %> <%@ Import Namespace="DataLayer" %> <%@ Import Namespace="System.Collections" %> <%@ Register TagPrefix="Categories" TagName="LeftNav" Src="Categories.ascx" %> <%@ Register TagPrefix="TopNav" TagName="TopNav" Src="TopNav.ascx" %> <%@ Page language="c#" CodeFile="CheckoutConfirmation.aspx.cs" AutoEventWireup="false" Inherits="CheckoutConfirmation" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3c.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3c.org/1999/xhtml"> <head> <title>Checkout Confirmation</title> </head> CHAPTER 15 ■ SECOND ITERATION260 4800ch15.qrk 5/23/06 8:20 PM Page 260 <body> <table id="Table1" cellspacing="1" cellpadding="1" width="100%" border="0"> <tr> <td colspan="2" style="height: 43px"> <TopNav:TopNav id="topnav" runat="server" /> </td> </tr> <tr> <td width="20%" valign="top" align="left"> <Categories:LeftNav id="leftnav" runat="server" /> </td> <td valign="top" align="left"> <table width="100%"> <tr> <th align="left"> Product</th> <th align="left"> Price</th> <th align="center"> Quantity</th> <th> </th> </tr> <% while ( cartEnumerator.MoveNext() ) { LineItem lineItem = (LineItem)cartEnumerator.Value; Product product = lineItem.Item; Response.Write("<tr><td>" + product.ProductName + "</td><td>" + product.Price.ToString("C") + "</td><td align=\"center\">" + lineItem.Quantity.ToString() + "</td></tr>"); } %> </table> </td> </tr> </table> </body> </html> Next, you need to add code to the CheckoutConfirmation.aspx.cs class to get the shop- ping cart from the session, as shown in Listing 15-15. CHAPTER 15 ■ SECOND ITERATION 261 4800ch15.qrk 5/23/06 8:20 PM Page 261 Listing 15-15. Modified CheckoutConfirmation.aspx.cs to Get the Shopping Cart using System; using System.Collections; using System.Configuration; using System.Data; using System.Drawing; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using BusinessLayer; using DataLayer; public partial class CheckoutConfirmation : System.Web.UI.Page { protected ShoppingCart cart = null; protected IDictionaryEnumerator cartEnumerator = null; protected void Page_Load(object sender, System.EventArgs e) { if ( Session["cart"] != null ) { cart = (ShoppingCart)Session["cart"]; } else { cart = new ShoppingCart(); cart.Quantity = 0; Session["cart"] = cart; } cartEnumerator = cart.GetCartContents(); } } Now when the users go to this page, if they have any items in their shopping cart, those items will be displayed. But this isn’t much different from the DisplayShoppingCart.aspx page. So, next you will subtotal the dollar amounts of all the items displayed. Subtotal Shopping Cart Line Items and Display Results Task To get the subtotal, you need to first enhance CheckoutConfirmation.aspx to display the subto- tal, as shown in Listing 15-16. CHAPTER 15 ■ SECOND ITERATION262 4800ch15.qrk 5/23/06 8:20 PM Page 262 [...]... FROM Products WHERE ProductID = "); commandText.Append(productID); dataCommand.CommandText = commandText.ToString(); OdbcDataReader dataReader = dataCommand.ExecuteReader(); if (dataReader.Read()) { product = new Product(); product.ProductID = dataReader.GetInt32(0); product.ProductName = dataReader.GetString(1); product.CategoryID = dataReader.GetInt32(3); product.Price = dataReader.GetDecimal(5); product.Quantity... dataReader.GetInt32(3); product.Price = dataReader.GetDecimal(5); product.Quantity = dataReader.GetInt16(6); products.Add(product); } 273 4800ch15.qrk 274 5/23/06 8:20 PM Page 274 CHAPTER 15 ■ SECOND ITERATION dataConnection.Close(); } catch(Exception e) { Console.WriteLine("Error: " + e.Message); } return products; } public static Product GetProduct(int ProductID) { Product product = null; try { OdbcConnection... FROM Products WHERE ProductName LIKE '%'); commandText.Append(searchString); commandText.Append("%'"); dataCommand.CommandText = commandText.ToString(); OdbcDataReader dataReader = dataCommand.ExecuteReader(); while (dataReader.Read()) { product = new Product(); product.ProductID = dataReader.GetInt32(0); product.ProductName = dataReader.GetString(1); product.CategoryID = dataReader.GetInt32(3); product.Price... StringBuilder("SELECT * FROM Products WHERE CategoryID="); commandText.Append(categoryID); commandText.Append(" AND UnitsInStock > 0"); dataCommand.CommandText = commandText.ToString(); OdbcDataReader dataReader = dataCommand.ExecuteReader(); while (dataReader.Read()) { Product product = new Product(); product.ProductID = dataReader.GetInt32(0); product.ProductName = dataReader.GetString(1); product.CategoryID... align="left"> Product Price Quantity Product Price Quantity . xmlns="http://www.w3c.org/ 199 9/xhtml"> <head> <title>Checkout Confirmation</title> </head> CHAPTER 15 ■ SECOND ITERATION 25 9 4 800 ch15.qrk 5 /23 /06 8 : 20 PM Page 25 9 <body> <table. xmlns="http://www.w3c.org/ 199 9/xhtml"> <head> <title>Checkout Confirmation</title> </head> CHAPTER 15 ■ SECOND ITERATION2 60 4 800 ch15.qrk 5 /23 /06 8 : 20 PM Page 26 0 <body> <table. System.Web.UI.Page { protected ShoppingCart cart = null; protected IDictionaryEnumerator cartEnumerator = null; protected decimal total = 0; CHAPTER 15 ■ SECOND ITERATION264 4 800 ch15.qrk 5 /23 /06 8 : 20 PM Page 26 4 protected