本主题适用于:
Visual Studio 旗舰版 |
Visual Studio 高级专业版 |
Visual Studio 专业版 |
Visual Studio 速成版 |
---|---|---|---|
![]() |
![]() |
![]() |
![]() |
本主题包含用于演示如何调试多层数据库应用程序的示例代码,并介绍需要执行哪些步骤才能将驻留在客户端或中间层应用程序的应用程序代码调试成在 SQL Server 实例(从 SQL Server 2005 开始)内部运行的数据库对象的 Transact-SQL 代码。
应用程序层和数据库层之间的转换需要目标层中存在断点;否则,尝试单步执行层时,代码将不间断地执行下去。但是,Transact-SQL 和数据库层内的 SQL CLR 代码之间的转换不需要断点来启用它们之间的单步执行。
下面的示例使用一个 C# 控制台应用程序、一个名为 Currency 的 SQL Server 数据库表以及两个在 C# 和 Transact-SQL 之间来回切换的存储过程。该示例的目的在于阐释这些转换,显然不是实务操作场景。
会调用两个存储过程:
DeleteCurrency 是一个 Transact-SQL 存储过程,可以用给定的货币代码删除货币。
DeleteCurrencyDriver 也是一个 Transact-SQL 存储过程。它使用一个指定要删除的货币代码的输入参数来调用前一个存储过程。
应用程序代码会调用这两个存储过程,传入货币代码参数。“非驱动程序”存储过程是从两个不同的上下文中调用的,即从 DeleteCurrencyDriver 调用和直接从相应的应用程序中调用。在第一个上下文中,通过单击**“单步执行”**按钮,将能够从 DeleteCurrencyDriver 进入并单步执行另一个存储过程。当从应用程序调用这两个存储过程时,将不能直接单步执行它们,而需要在它们内部设置断点。
创建用于本次演示的 Transact-SQL 数据库对象
在 SQL Server 2005 或所选的更高数据库版本中,使用第一个示例中的代码创建 Currency 表和两个存储过程。
打开 Visual Studio 中的 Transact-SQL 编辑器,并连接到可用于此演示的数据库。有关更多信息,请参见如何:启动 Transact-SQL 编辑器和如何:连接到 Transact-SQL 编辑器中的数据库。
复制第一个示例中的 Transact-SQL 代码,并将其粘贴到 Transact-SQL 编辑器中。
用适当的数据库名称替换 <database>,再单击**“Transact-SQL 编辑器”工具栏中的“执行 SQL”**。
如果在 SQL Server 数据库或服务器项目的上下文中打开了 Transact-SQL 编辑器,请在继续操作之前关闭该项目。否则,可以将 Transact-SQL 编辑器保持打开状态并继续操作。
为多层调试准备好服务器资源管理器
确保已为计算机启用了 Transact-SQL 调试。有关更多信息,请参见如何:启用 Transact-SQL 调试。
打开**“视图”菜单并单击“服务器资源管理器”,将“服务器资源管理器”**打开。
在**“服务器资源管理器”中,右击“数据连接”并选择“添加连接”,创建新数据连接。这将启动“添加连接”**对话框。
创建到相应数据库的连接,即您创建 Currency 表时所在的数据库。该连接所用的登录名必须是 sysadmin 固定服务器角色的成员,这一点至关重要。有关更多信息,请参见如何:使用服务器资源管理器连接到数据库。
创建新数据连接之后,请在**“数据连接”**节点下找到它。
右击新数据连接,再单击**“应用程序调试”**。这会对连接中指定的数据库启用多层调试。
准备好要进行多层调试的 C# 控制台应用程序
在准备**“服务器资源管理器”**的 Visual Studio 实例中,准备一个 C# 控制台应用程序,该程序将执行 DeleteCurrencyDriver 和 DeleteCurrency 存储过程。
打开**“文件”菜单并单击“新建项目”**,可打开新的 C# 控制台应用程序。
复制第二个示例中的 C# 代码,并用它来替换项目所创建的 Program.cs 文件中的所有代码。
在控制台应用程序属性的**“调试”选项卡上,选中“启用 SQL Server 调试”**。这将为控制台应用程序启用多层调试。有关更多信息,请参见如何:为 C++、Visual Basic 或 C# 项目启用 Transact-SQL 调试。
调试多层控制台应用程序
在 C# 代码中(Program.cs 文件),将断点放置在每次调用存储过程之前和之后。
在存储过程中放置断点。注意:不能从 C# 代码中单步执行 Transact-SQL 代码,但可以在 SQL Server 数据库对象之间切换。
在**“服务器资源管理器”**中,在新数据连接下找到新存储过程。
右击**“DeleteCurrency”存储过程,再单击“打开”**。这将启动 Transact-SQL 编辑器窗口,显示 DeleteCurrency 存储过程。单击编辑器左侧的灰条,在 SET NOCOUNT ON 行中设置断点。
右击**“DeleteCurrencyDriver”存储过程,再单击“打开”**。Transact-SQL 编辑器窗口随即启动,其中显示了 DeleteCurrencyDriver 存储过程。单击编辑器左侧的灰条,在 SET NOCOUNT ON 行中设置断点。
按 F5 运行应用程序。
逐句通过不同的模块。
试着删除一些断点,以查看在不同层和语言之间切换的尝试效果。
若要完成调试,请从 Visual Studio 的**“调试”**菜单中清除所有断点,并按 F5。
示例
本节所包含的 Transact-SQL 代码可创建 Currency 表和两个存储过程:DeleteCurrency 和 DeleteCurrencyDriver。 请用相应的数据库名称替换 <database>。
USE <database>
GO
CREATE TABLE Currency
(CurrencyCode nvarchar(1))
INSERT Currency
VALUES (N'A'),(N'B'),(N'C'),(N'D')
SELECT * FROM Currency
GO
CREATE PROCEDURE dbo.DeleteCurrency
(
@CurrencyCode nvarchar(3)
)
AS
SET NOCOUNT ON
DELETE Currency
WHERE CurrencyCode = @currencyCode
RETURN
GO
CREATE PROCEDURE dbo.DeleteCurrencyDriver
(
@CurrencyCode nvarchar(3)
)
AS
SET NOCOUNT ON
EXECUTE DeleteCurrency @CurrencyCode
RETURN
GO
本节包含控制台应用程序的 C# 代码,这些代码可以调用 DeleteCurrencyDriver 和 DeleteCurrency 存储过程。分别用 Currency 表所驻留的实例和数据库名称替换 <server> 和 <database>。
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, 1);
procCommand.Parameters["@CurrencyCode"].Value = "B";
try { procCommand.ExecuteNonQuery(); }
catch (SqlException e) { Console.WriteLine(e.Message); }
//Execute DeleteCurrency stored procedure directly
procCommand.CommandText = "DeleteCurrency";
try { procCommand.ExecuteNonQuery(); }
catch (SqlException e) { Console.WriteLine(e.Message); }
SqlConnection1.Close();
Console.WriteLine("Press any key to close...");
Console.Read();
}
}
}