更新:2007 年 11 月
本主题适用于:
版本 |
Visual Basic |
C# |
C++ |
Web Developer |
---|---|---|---|---|
速成版 |
![]() |
![]() |
![]() |
![]() |
标准版 |
![]() |
![]() |
![]() |
![]() |
专业团队版 |
![]() |
![]() |
![]() |
![]() |
表格图例:
![]() |
适用 |
![]() |
不适用 |
![]() |
默认情况下隐藏的一条或多条命令。 |
本主题包含演示如何调试多层应用程序的示例代码,并介绍从驻留在客户端或中间层应用程序中的应用程序代码进入在 SQL Server 2005 中运行的数据库对象的代码所需的调试步骤。
应用程序层与数据库层之间的转换要求在目标层中设置断点;否则,在尝试单步执行目标层时,只执行代码而不会停止。但是数据库层内部的 T-SQL 代码和 SQL CLR 代码之间的转换不需要断点就可以在这两者之间单步执行。
下面示例使用 AdventureWorks 数据库,并在不同层及不同语言之间来回执行单步调试。该示例旨在阐释这些转换,显然不是实际的业务方案。
示例调用三个存储过程:
DeleteCurrency 是一个 SQL CLR 存储过程,它删除具有给定货币代码的货币。
DeleteCurrency_T_SQL 执行同一操作,但是它是用 T-SQL 编写的。
DeleteCurrencyDriver 调用上述两个存储过程,它有一个输入参数,该参数指定要删除的货币的代码。
应用程序代码调用这三个存储过程,并传入货币代码参数。从两种不同的上下文(即从 DeleteCurrencyDriver 和直接从应用程序)调用两个“非驱动程序”存储过程。在第一个上下文中,可以从 DeleteCurrencyDriver 单步进入其他两个存储过程。从应用程序调用它们时,不能直接单步进入它们,而必须在存储过程中设置断点。
调试数据库应用程序
在一个新的 SQL Server 项目中,建立一个到 AdventureWorks 数据库的连接。有关更多信息,请参见如何:连接到数据库。
使用下面第一个示例部分中的代码创建 T-SQL 存储过程,并将其命名为 DeleteCurrency_T_SQL。有关此步骤或此过程中任何步骤的更多信息,请参见 如何:使用 SQL Server 项目类型进行开发。
使用下面第二个示例部分中的代码创建一个 SQL CLR 存储过程,并将其命名为 DeleteCurrency.cs。
使用下面第三个示例部分中的代码创建一个 SQL CLR 存储过程,并将其命名为 DeleteCurrencyDriver。
在“调试”菜单上单击“开始”,将这些更改编译并部署到 AdventureWorks 数据库中。
在每个存储过程中至少设置一个断点。从本机代码或托管代码无法进入并单步执行存储过程。
在 Visual Studio 中创建新的控制台项目。
将第四个示例中的代码粘贴到文本编辑器中。
在对存储过程的每个调用前后放置断点。
按 F5 运行应用程序。
逐句通过不同的模块。
尝试移除一些断点来查看尝试在不同层及不同语言之间进出的效果。
若要完成调试,请从 Visual Studio“调试”菜单中清除所有断点,然后按 F5。
示例
本节包含 T-SQL 存储过程的代码。
CREATE PROCEDURE dbo.DeleteCurrency_T_SQL
(
@CurrencyCode nvarchar(3)
)
AS
SET NOCOUNT ON
DELETE Sales.Currency
WHERE CurrencyCode = @currencyCode
RETURN
此代码包含从驱动程序存储过程调用的 SQL CLR 存储过程的代码。
using System;
using System.Data.SqlTypes;
using System.Data.SqlClient;
using Microsoft.SqlServer.Server;
public partial class StoredProcedures
{
[SqlProcedure]
public static void DeleteCurrency(SqlString currencyCode)
{
string sCmd = "DELETE Sales.Currency WHERE CurrencyCode = '" + currencyCode.Value + "'";
SqlConnection conn = new SqlConnection("Context Connection=True");
conn.Open();
SqlCommand DeleteCurrencyCommand = new SqlCommand( sCmd , conn);
DeleteCurrencyCommand.ExecuteNonQuery();
}
}
此代码包含调用其他过程的 SQL CLR 驱动程序过程的代码。此存储过程从应用程序层进行调用。
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
public partial class StoredProcedures
{
[SqlProcedure]
public static void DeleteCurrencyDriver(SqlString CurrencyCode)
{
string sCommand = "DELETE Sales.Currency WHERE CurrencyCode = '" + CurrencyCode.Value + "'";
SqlConnection conn = new SqlConnection("Context Connection=True");
conn.Open();
SqlCommand DeleteCurrencyCommand = new SqlCommand(sCommand, conn);
DeleteCurrencyCommand.ExecuteNonQuery();
// Now execute a T-SQL stored procedure.
DeleteCurrencyCommand.CommandType = CommandType.StoredProcedure;
DeleteCurrencyCommand.CommandText = "DeleteCurrency_T_SQL";
// Fill the parameters collection based upon stored procedure.
SqlParameter workParam = null;
workParam = DeleteCurrencyCommand.Parameters.Add("@CurrencyCode", SqlDbType.NChar, 3);
DeleteCurrencyCommand.Parameters["@CurrencyCode"].Value = "ESC";
try { DeleteCurrencyCommand.ExecuteNonQuery(); }
catch { }
// Now execute a CLR stored procedure.
DeleteCurrencyCommand.CommandText = "DeleteCurrency";
try { DeleteCurrencyCommand.ExecuteNonQuery(); }
catch { }
}
};
此代码包含将调用驱动程序存储过程(同时直接调用 T-SQL 和 SQL CLR 存储过程)的应用程序代码。
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
builder.DataSource = <server>;
builder.IntegratedSecurity = true;
builder.InitialCatalog = <database>;
SqlConnection SqlConnection1 = new SqlConnection(builder.ConnectionString);
SqlConnection1.Open();
SqlCommand procCommand = new SqlCommand();
procCommand.CommandText = "DeleteCurrencyDriver";
procCommand.CommandType = CommandType.StoredProcedure;
procCommand.Connection = SqlConnection1;
// Fill parameters collection for the stored procedure.
SqlParameter workParam = null;
workParam = procCommand.Parameters.Add("@CurrencyCode", SqlDbType.NChar, 3);
procCommand.Parameters["@CurrencyCode"].Value = "ESC";
try { procCommand.ExecuteNonQuery(); }
catch (SqlException e) { DumpException(e); }
procCommand.CommandText = "DeleteCurrency";
try { procCommand.ExecuteNonQuery(); }
catch (SqlException e) { DumpException(e); }
procCommand.CommandText = "DeleteCurrency_T_SQL";
try { procCommand.ExecuteNonQuery(); }
catch (SqlException e) { DumpException(e); }
SqlConnection1.Close();
}
static void DumpException(SqlException e)
{
string errorMessages = "";
for (int i = 0; i < e.Errors.Count; i++)
{
errorMessages += "Index #" + i + "\n" +
"Message: " + e.Errors[i].Message + "\n" +
"LineNumber: " + e.Errors[i].LineNumber + "\n" +
"Source: " + e.Errors[i].Source + "\n" +
"Procedure: " + e.Errors[i].Procedure + "\n";
}
System.Diagnostics.EventLog log = new System.Diagnostics.EventLog();
log.Source = "My Application";
log.WriteEntry(errorMessages);
Console.WriteLine("An exception occurred. Please contact your system administrator.");
}
}
}