Creating the User-Defined Type After you have loaded the DBMovie assembly, you can create a new user-defined type from the assembly.. Execute the following command: CREATE TYPE dbo.DBMov
Trang 1Creating the User-Defined Type
After you have loaded the DBMovie assembly, you can create a new user-defined type
from the assembly Execute the following command:
CREATE TYPE dbo.DBMovie EXTERNAL NAME DBMovie.DBMovie
If you need to delete the type, you can execute the following command:
DROP TYPE DBMovie
After you have added the type, you can use it just like any other SQL Server native type
For example, you can create a new database table with the following command:
CREATE TABLE DBMovies(Id INT IDENTITY, Movie DBMovie)
You can insert a new record into this table with the following command:
INSERT DBMovies (Movie)
VALUES (‘Star Wars,George Lucas,12.34’)
Finally, you can perform queries against the table with queries like the following:
SELECT Id, Movie FROM DBMovies WHERE Movie.BoxOfficeTotals > 13.23
SELECT MAX(Movie.BoxOfficeTotals) FROM DBMovies
SELECT Movie FROM DBMovies WHERE Movie.Director LIKE ‘g%’
I find the fact that you can execute queries like this truly amazing
Building a Data Access Layer with a User-Defined Type
In this final section, let’s actually do something with our new user-defined type We create
a new data access component that uses the DBMovie class and an ASP.NET page that
inter-faces with the component
Before we can do anything with the DBMovie type, we need to add a reference to the
DBMovie.dll assembly to our application In Visual Web Developer, select Website, Add
Reference, and browse to the DBMovie.dll Alternatively, you can create an application
root Bin folder and copy the DBMovie.dll into the Bin folder
Our new data access component is contained in Listing 19.37
LISTING 19.37 App_Code\DBDataLayer.cs
using System;
using System.Data;
using System.Data.SqlClient;
using System.Web.Configuration;
Trang 2public class DBDataLayer
{
private static readonly string _connectionString;
public List<DBMovie> GetAll()
{
List<DBMovie> results = new List<DBMovie>();
SqlConnection con = new SqlConnection(_connectionString);
SqlCommand cmd = new SqlCommand(“SELECT Movie FROM DBMovies”, con);
using (con)
{
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
DBMovie newMovie = (DBMovie)reader[“Movie”];
results.Add(newMovie);
}
}
return results;
}
public void Insert(DBMovie movieToAdd)
{
SqlConnection con = new SqlConnection(_connectionString);
SqlCommand cmd = new SqlCommand(“INSERT DBMovies (Movie) VALUES (@Movie)”,
➥con);
cmd.Parameters.Add(“@Movie”, SqlDbType.Udt);
cmd.Parameters[“@Movie”].UdtTypeName = “DBMovie”;
cmd.Parameters[“@Movie”].Value = movieToAdd;
using (con)
{
con.Open();
cmd.ExecuteNonQuery();
}
}
static DBDataLayer()
{
_connectionString =
WebConfigurationManager.ConnectionStrings[“Movies”].ConnectionString;
}
}
Trang 3The component in Listing 19.37 contains two methods: GetAll() and Insert() The
GetAll() method retrieves all the Movie objects from the DBMovies database table You
can cast the object represented by the DataReader directly to a DBMovie
The Insert() method adds a new DBMovie to the DBMovies database table The method
creates a normal ADO.NET Command object However, a special parameter is added to the
command that represents the DBMovie object
When you create a parameter that represents a user-defined type, you must specify a
UdtTypeName property that represents the name of the user-defined type In Listing 19.37,
the value DBMovie is assigned to the UdtTypeName property When the command executes,
a new DBMovie object is added to the DBMovies database table
The page in Listing 19.38 contains a GridView, DetailsView, and ObjectDataSource control
The GridView displays all the movies from the DBMovies database table The DetailsView
control enables you to insert a new DBMovie into the database (see Figure 19.21)
FIGURE 19.21 Displaying and inserting DBMovie objects
LISTING 19.38 ShowDBDataLayer.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” >
Trang 4<title>Show DBDataLayer</title>
</head>
<body>
<form id=”form1” runat=”server”>
<div>
<asp:GridView
id=”grdMovies”
DataSourceID=”srcMovies”
Runat=”server” />
<br />
<fieldset>
<legend>Add Movie</legend>
<asp:DetailsView
id=”dtlMovie”
DataSourceID=”srcMovies”
DefaultMode=”Insert”
AutoGenerateInsertButton=”true”
AutoGenerateRows=”false”
Runat=”server”>
<Fields>
<asp:BoundField DataField=”Title” HeaderText=”Title” />
<asp:BoundField DataField=”Director” HeaderText=”Director” />
<asp:BoundField DataField=”BoxOfficeTotals”
HeaderText=”Box Office Totals” />
</Fields>
</asp:DetailsView>
</fieldset>
<asp:ObjectDataSource
id=”srcMovies”
TypeName=”DBDataLayer”
DataObjectTypeName=”DBMovie”
SelectMethod=”GetAll”
InsertMethod=”Insert”
Runat=”server” />
</div>
</form>
</body>
</html>
Trang 5Creating Stored Procedures with NET Framework
You can use NET Framework to build a SQL stored procedure by mapping a stored
proce-dure to a method defined in a class You must complete the following steps:
Create an assembly that contains the stored procedure method
Register the assembly with SQL Server
Create a stored procedure based on the assembly
In this section, we create two stored procedures with NET Framework The first stored
procedure, named GetRandomRow(), randomly returns a single row from a database table
The second stored procedure, GetRandomRows(), randomly returns a set of rows from a
database table
Creating the Stored Procedure Assembly
Creating a stored procedure with NET Framework is easy All you need to do is decorate
a method with the SqlProcedure attribute
The method used for the stored procedure must satisfy two requirements The method
must be a shared (static) method Furthermore, the method must be implemented either
as a subroutine or as a function that returns an integer value
Within your method, you can take advantage of the SqlPipe class to send results back to
your application The SqlPipe class supports the following methods:
Send()—Enables you to send a DataReader, single-row resultset, or string
ExecuteAndSend()—Enables you to execute a SqlCommand and send the results
SendResultsStart()—Enables you to initiate the sending of a resultset
SendResultsRow()—Enables you to send a single row of a resultset
SendResultsEnd()—Enables you to end the sending of a resultset
Within the method used for creating the stored procedure, you can use ADO.NET objects
such as the SqlCommand, SqlDataReader, and SqlDataAdapter objects in the normal way
However, rather than connect to the database by using a normal connection string, you
can create something called a context connection A context connection enables you to
connect to the same database server as the stored procedure without authenticating
Here’s how you can initialize a SqlConnection to use a context connection:
SqlConnection con = new SqlConnection(“context connection=true”);
You don’t specify credentials or the location of the database in the connection string
Remember that the method actually executes within SQL Server Therefore, you don’t
need to connect to SQL Server in the normal way
Trang 6contents of the Movies database table The GetRandomRow() method grabs a single row
from the DataTable and sends it back to the client The GetRandomRows() method sends
multiple rows back to the client
LISTING 19.39 RandomRows.cs
using System;
using System.Data;
using System.Data.SqlClient;
using Microsoft.SqlServer.Server;
public class RandomRows
{
[SqlProcedure]
public static void GetRandomRow()
{
// Dump all records from Movies into a DataTable
SqlDataAdapter dad = new SqlDataAdapter(
“SELECT Id,Title FROM Movies”, “context connection=true”);
DataTable dtblMovies = new DataTable();
dad.Fill(dtblMovies);
// Grab a random row
Random rnd = new Random();
DataRow ranRow = dtblMovies.Rows[rnd.Next(dtblMovies.Rows.Count)];
// Build a SqlDataRecord that represents the row
SqlDataRecord result = new SqlDataRecord(
new SqlMetaData(“Id”, SqlDbType.Int), new SqlMetaData(“Title”, SqlDbType.NVarChar,
➥100));
result.SetSqlInt32(0, (int)ranRow[“Id”]);
result.SetSqlString(1, (string)ranRow[“Title”]);
// Send result
SqlContext.Pipe.Send(result);
}
[SqlProcedure]
public static void GetRandomRows(int rowsToReturn)
{
// Dump all records from Movies into a DataTable
SqlDataAdapter dad = new SqlDataAdapter(
“SELECT Id,Title FROM Movies”, “context connection=true”);
DataTable dtblMovies = new DataTable();
dad.Fill(dtblMovies);
Trang 7// Send start record
SqlDataRecord result = new SqlDataRecord(new SqlMetaData(“Id”,
SqlDbType.Int),new SqlMetaData(“Title”, SqlDbType.NVarChar, 100));
SqlContext.Pipe.SendResultsStart(result);
Random rnd = new Random();
for (int i = 0; i < rowsToReturn; i++)
{
// Grab a random row
DataRow ranRow = dtblMovies.Rows[rnd.Next(dtblMovies.Rows.Count)];
// Set the record
result.SetSqlInt32(0, (int)ranRow[“Id”]);
result.SetSqlString(1, (string)ranRow[“Title”]);
// Send record
SqlContext.Pipe.SendResultsRow(result);
}
// Send end record
SqlContext.Pipe.SendResultsEnd();
}
}
You need to compile the RandomRows class into a separate assembly (.dll file) After you
create (and debug) the class, move the class from your App_Code folder to another folder
in your application, such as the root folder Next, open the SDK Command prompt and
execute the following command:
csc /t:library RandomRows.cs
This command uses the C# command-line compiler to compile the RandomRows class into
an assembly
Registering the Stored Procedure Assembly with SQL Server
After you compile the RandomRows assembly, you are ready to deploy the assembly to SQL
Server You can load the assembly into SQL Server by executing the following command:
CREATE ASSEMBLY RandomRows
FROM ‘C:\RandomRows.dll’
You need to supply the proper path to the RandomRows.dll assembly on your hard drive If
you need to remove the assembly, you can execute the following command:
Trang 8Creating the Stored Procedures
Now that the assembly is loaded, you can create two stored procedures that correspond to
the two methods defined in the assembly Execute the following two SQL commands:
CREATE PROCEDURE GetRandomRow AS
EXTERNAL NAME RandomRows.RandomRows.GetRandomRow
CREATE PROCEDURE GetRandomRows(@rowsToReturn Int) AS
EXTERNAL NAME RandomRows.RandomRows.GetRandomRows
After you execute these two commands, you have two new stored procedures named
GetRandomRow and GetRandomRows You can treat these stored procedures just like normal
stored procedures For example, executing the following command displays three random
movies from the Movies database:
GetRandomRows 3
If you need to delete these stored procedures, you can execute the following two commands:
DROP PROCEDURE GetRandomRow
DROP PROCEDURE GetRandomRows
Executing a NET Stored Procedure from an ASP.NET Page
After the two stored procedures have been created, you can use the stored procedures with
an ASP.NET page For example, the component in Listing 19.40 contains two methods
that call the two stored procedures
LISTING 19.40 App_Code\RandomDataLayer.cs
using System;
using System.Data;
using System.Data.SqlClient;
using System.Web.Configuration;
using System.Collections.Generic;
public class RandomDataLayer
{
private static readonly string _connectionString;
public List<String> GetRandomMovies()
{
List<String> results = new List<String>();
SqlConnection con = new SqlConnection(_connectionString);
SqlCommand cmd = new SqlCommand(“GetRandomRows”, con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue(“@rowsToReturn”, 5);
Trang 9using (con)
{
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
results.Add((string)reader[“Title”]);
}
return results;
}
public static string GetRandomMovie()
{
string result = String.Empty;
SqlConnection con = new SqlConnection(_connectionString);
SqlCommand cmd = new SqlCommand(“GetRandomRow”, con);
cmd.CommandType = CommandType.StoredProcedure;
using (con)
{
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
result = (string)reader[“Title”];
}
return result;
}
static RandomDataLayer()
{
_connectionString =
WebConfigurationManager.ConnectionStrings[“Movies”].ConnectionString;
}
}
In Listing 19.40, the GetRandomRow and GetRandomRows stored procedures are executed with
the help of SqlCommand objects
The page in Listing 19.41 contains a GridView and ObjectDataSource control The
ObjectDataSource control represents the RandomDataLayer component When you request
the page, a single random movie title displays in a Label control Furthermore, a list of
five random movie titles displays in the GridView control (see Figure 19.22)
Trang 10LISTING 19.41 ShowRandomDataLayer.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”>
void Page_Load()
{
lblRandomMovie.Text = RandomDataLayer.GetRandomMovie();
}
</script>
<html xmlns=”http://www.w3.org/1999/xhtml” >
<head id=”Head1” runat=”server”>
<title>Show RandomDataLayer</title>
</head>
<body>
<form id=”form1” runat=”server”>
<div>
Random Movie:
<asp:Label
id=”lblRandomMovie”
FIGURE 19.22 Calling a NET stored procedure from an ASP.NET page