ptg 864 CHAPTER 19 Building Data Access Components with ADO.NET The first statement creates a SqlCommand object that represents a SQL INSERT command. The command includes a parameter named @Title. The second statement adds a SqlParameter to the SqlCommand object’s Parameters collec- tion. The AddWithValue() method enables you to add a parameter with a certain name and value. In this case, the method supplies the value for the @Title parameter. When you execute the SqlCommand, the following command is sent to Microsoft SQL Server: exec sp_executesql N’INSERT Titles (Title) VALUES (@Title)’, ➥ N’@Title nvarchar(17)’, @Title = N’ASP.NET 4.0 Unleashed’ The SqlCommand object calls the sp_executesql stored procedure when it executes a command. In this case, it passes the type, size, and value of the @Title parameter to the sp_executesql stored procedure. When you use AddWithValue(), the SqlCommand object infers the type and size of the para- meter for you. The method assumes that string values are SQL NVarChar values, integer values are SQL Int values, decimal values are SQL decimal values, and so on. As an alternative to using the AddWithValue() method, you can create a SqlParameter explicitly and add the SqlParameter to a SqlCommand object’s Parameters collection. The advantage of creating a parameter explicitly is that you can specify parameter properties explicitly, such as its name, type, size, precision, scale, and direction. For example, the following code creates a parameter named @Title with a particular data type, size, and value: SqlCommand cmd = new SqlCommand(“INSERT Titles (Title) VALUES (@Title)”, con); SqlParameter paramTitle = new SqlParameter(); paramTitle.ParameterName = “@Title”; paramTitle.SqlDbType = SqlDbType.NVarChar; paramTitle.Size = 50; paramTitle.Value = “ASP.NET 4.0 Unleashed”; cmd.Parameters.Add(paramTitle); If this seems like a lot of code to do something simple, you can use one of the overloads of the Add() method to create a new SqlParameter like this: SqlCommand cmd = new SqlCommand(“INSERT Test (Title) VALUES (@Title)”, con); cmd.Parameters.Add(“@Title”, SqlDbType.NVarChar,50).Value = “ASP.NET 4.0 ➥ Unleashed”; In general, in this book and in the code that I write, I use the AddWithValue() method to create parameters. I like the AddWithValue() method because it involves the least typing. From the Library of Wow! eBook ptg 865 Connected Data Access 19 Executing a Command That Represents a Stored Procedure You can use a SqlCommand object to represent a Microsoft SQL Server stored procedure. For example, you can use the following two statements to create a SqlCommand object that represents a stored procedure named GetTitles: SqlCommand cmd = new SqlCommand(“GetTitles”, con); cmd.CommandType = CommandType.StoredProcedure; When you execute this SqlCommand, the GetTitles stored procedure is executed. When you create SqlParameters for a SqlCommand that represents a stored procedure, the SqlParameters represent stored procedure parameters. The modified Movie component in Listing 19.9 uses stored procedures to retrieve and update movie records. LISTING 19.9 App_Code\Movie4.cs using System; using System.Data; using System.Data.SqlClient; using System.Web.Configuration; using System.Collections.Generic; public class Movie4 { private static readonly string _connectionString; private int _id; private string _title; private string _director; public int Id { get { return _id; } set { _id = value; } } public string Title { get { return _title; } set { _title = value; } } public string Director { get { return _director; } set { _director = value; } } From the Library of Wow! eBook ptg 866 CHAPTER 19 Building Data Access Components with ADO.NET public void Update(int id, string title, string director) { SqlConnection con = new SqlConnection(_connectionString); SqlCommand cmd = new SqlCommand(“MovieUpdate”, con); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue(“@Id”, id); cmd.Parameters.AddWithValue(“@Title”, title); cmd.Parameters.AddWithValue(“@Director”, director); using (con) { con.Open(); cmd.ExecuteNonQuery(); } } public List<Movie4> GetAll() { List<Movie4> results = new List<Movie4>(); SqlConnection con = new SqlConnection(_connectionString); SqlCommand cmd = new SqlCommand(“MovieSelect”, con); cmd.CommandType = CommandType.StoredProcedure; using (con) { con.Open(); SqlDataReader reader = cmd.ExecuteReader(); while (reader.Read()) { Movie4 newMovie = new Movie4(); newMovie.Id = (int)reader[“Id”]; newMovie.Title = (string)reader[“Title”]; newMovie.Director = (string)reader[“Director”]; results.Add(newMovie); } } return results; } static Movie4() { _connectionString = WebConfigurationManager.ConnectionStrings[“Movies”].ConnectionString; } } The component in Listing 19.9 uses the MovieSelect and MovieUpdate stored procedures contained in Listing 19.10. From the Library of Wow! eBook ptg 867 Connected Data Access 19 LISTING 19.10 MovieStoredProcedures.sql CREATE PROCEDURE dbo.MovieSelect AS SELECT Id, Title, Director FROM Movies CREATE PROCEDURE dbo.MovieUpdate ( @Id int, @Title NVarchar(100), @Director NVarchar(100) ) AS UPDATE Movies SET Title = @Title, Director = @Director WHERE Id = @Id The ASP.NET page in Listing 19.11 contains a GridView that is bound to the modified Movie component. This GridView enables you to display and update movie records. LISTING 19.11 ShowMovie4.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <html xmlns=”http://www.w3.org/1999/xhtml” > <head id=”Head1” runat=”server”> <title>Show Movie4</title> </head> <body> <form id=”form1” runat=”server”> <div> <asp:GridView id=”grdMovies” DataSourceID=”srcMovies” DataKeyNames=”Id” AutoGenerateEditButton=”true” Runat=”server” /> <asp:ObjectDataSource id=”srcMovies” TypeName=”Movie4” SelectMethod=”GetAll” From the Library of Wow! eBook ptg 868 CHAPTER 19 Building Data Access Components with ADO.NET UpdateMethod=”Update” Runat=”server” /> </div> </form> </body> </html> You can use a SqlParameter to represent not only stored procedure input parameters, but also to represent stored procedure return values and output parameters. If you need to return an integer value from a stored procedure, you can create a SqlParameter that repre- sents a return value. For example, the stored procedure in Listing 19.12 returns the number of rows in the Movies database table. LISTING 19.12 GetMovieCount.sql CREATE PROCEDURE dbo.GetMovieCount AS RETURN (SELECT COUNT(*) FROM Movies) The page in Listing 19.13 displays the return value from the GetMovieCount stored proce- dure with a Label control (see Figure 19.6). FIGURE 19.6 Displaying a stored procedure return value. From the Library of Wow! eBook ptg 869 Connected Data Access 19 LISTING 19.13 ShowMovieCount.aspx <%@ Page Language=”C#” %> <%@ Import Namespace=”System.Data” %> <%@ Import Namespace=”System.Data.SqlClient” %> <%@ Import Namespace=”System.Web.Configuration” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> void Page_Load() { lblMovieCount.Text = GetMovieCount().ToString(); } private int GetMovieCount() { int result = 0; string connectionString = WebConfigurationManager.ConnectionStrings[“Movies”].ConnectionString; SqlConnection con = new SqlConnection(connectionString); SqlCommand cmd = new SqlCommand(“GetMovieCount”, con); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add(“@ReturnVal”, SqlDbType.Int).Direction = ➥ ParameterDirection.ReturnValue; using (con) { con.Open(); cmd.ExecuteNonQuery(); result = (int)cmd.Parameters[“@ReturnVal”].Value; } return result; } </script> <html xmlns=”http://www.w3.org/1999/xhtml” > <head id=”Head1” runat=”server”> <title>Show Movie Count</title> </head> <body> <form id=”form1” runat=”server”> <div> There are <asp:Label id=”lblMovieCount” Runat=”server” /> From the Library of Wow! eBook ptg 870 CHAPTER 19 Building Data Access Components with ADO.NET movies in the database. </div> </form> </body> </html> In Listing 19.13, a SqlParameter is created that has the name ReturnVal. The name of the SqlParameter is not important. However, the SqlParameter.Direction property is set to the value ReturnValue. After the SqlCommand is executed, the return value can be retrieved by reading the value of this parameter. A stored procedure has only one return value, and it must be an integer value. If you need to return more than one value, or values of a different data type than an integer, you need to use stored procedure output parameters. For example, the stored procedure in Listing 19.14 returns movie titles and box office totals. The stored procedure includes an output parameter named @SumBoxOfficeTotals. This output parameter represents a sum of all box office totals. LISTING 19.14 GetBoxOfficeTotals.sql CREATE PROCEDURE dbo.GetBoxOfficeTotals ( @SumBoxOfficeTotals Money OUTPUT ) AS Assign Sum Box Office Totals SELECT @SumBoxOfficeTotals = SUM(BoxOfficeTotals) FROM Movies Return all rows SELECT Title, BoxOfficeTotals FROM Movies The data access component in Listing 19.15 contains a method named GetBoxOffice() that calls the GetBoxOfficeTotals stored procedure. The method adds an output parame- ter to the SqlCommand object. LISTING 19.15 App_Code\Movie5.cs using System; using System.Data; using System.Data.SqlClient; using System.Web.Configuration; using System.Collections.Generic; public class Movie5 From the Library of Wow! eBook ptg 871 Connected Data Access 19 { private static readonly string _connectionString; private string _title; private decimal _boxOfficeTotals; public string Title { get { return _title; } set { _title = value; } } public decimal BoxOfficeTotals { get { return _boxOfficeTotals; } set { _boxOfficeTotals = value; } } public List<Movie5> GetBoxOffice(out decimal SumBoxOfficeTotals) { List<Movie5> results = new List<Movie5>(); SqlConnection con = new SqlConnection(_connectionString); SqlCommand cmd = new SqlCommand(“GetBoxOfficeTotals”, con); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add(“@SumBoxOfficeTotals”, SqlDbType.Money).Direction = ParameterDirection.Output; using (con) { con.Open(); SqlDataReader reader = cmd.ExecuteReader(); while (reader.Read()) { Movie5 newMovie = new Movie5(); newMovie.Title = (string)reader[“Title”]; newMovie.BoxOfficeTotals = (decimal)reader[“BoxOfficeTotals”]; results.Add(newMovie); } reader.Close(); SumBoxOfficeTotals = ➥ (decimal)cmd.Parameters[“@SumBoxOfficeTotals”].Value; } return results; } From the Library of Wow! eBook ptg 872 CHAPTER 19 Building Data Access Components with ADO.NET static Movie5() { _connectionString = WebConfigurationManager.ConnectionStrings[“Movies”].ConnectionString; } } In Listing 19.15, the SqlDataReader is explicitly closed before the output parameter is read. If you do not close the SqlDataReader first, attempting to read the value of the output parameter raises an exception. Finally, the page in Listing 19.16 displays the movie box office totals in a GridView. In addition, it displays the value of the output parameter in a Label control (see Figure 19.7). FIGURE 19.7 Displaying an output parameter. LISTING 19.16 ShowMovie5.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> protected void srcMovies_Selected(object sender, ➥ ObjectDataSourceStatusEventArgs e) From the Library of Wow! eBook ptg 873 Connected Data Access 19 { decimal sum = (decimal)e.OutputParameters[“SumBoxOfficeTotals”]; lblSum.Text = sum.ToString(“c”); } </script> <html xmlns=”http://www.w3.org/1999/xhtml” > <head id=”Head1” runat=”server”> <title>Show Movie5</title> </head> <body> <form id=”form1” runat=”server”> <div> <asp:GridView id=”grdMovies” DataSourceID=”srcMovies” AutoGenerateColumns=”false” Runat=”server”> <Columns> <asp:BoundField DataField=”Title” HeaderText=”Title” /> <asp:BoundField DataField=”BoxOfficeTotals” HeaderText=”Box Office” HtmlEncode=”false” DataFormatString=”{0:c}” /> </Columns> </asp:GridView> <br /> Sum of Box Office Totals: <asp:Label id=”lblSum” Runat=”server” /> <asp:ObjectDataSource id=”srcMovies” TypeName=”Movie5” SelectMethod=”GetBoxOffice” Runat=”server” OnSelected=”srcMovies_Selected”> <SelectParameters> <asp:Parameter Name=”SumBoxOfficeTotals” Type=”Decimal” Direction=”Output” /> </SelectParameters> </asp:ObjectDataSource> From the Library of Wow! eBook . con); SqlParameter paramTitle = new SqlParameter(); paramTitle.ParameterName = “@Title”; paramTitle.SqlDbType = SqlDbType.NVarChar; paramTitle.Size = 50; paramTitle.Value = ASP. NET 4. 0 Unleashed”;. a SqlParameter explicitly and add the SqlParameter to a SqlCommand object’s Parameters collection. The advantage of creating a parameter explicitly is that you can specify parameter properties. SqlParameters represent stored procedure parameters. The modified Movie component in Listing 19.9 uses stored procedures to retrieve and update movie records. LISTING 19.9 App_CodeMovie4.cs using