|
5. 返回值 对函数返回值的处理不同于存储过程返回值的处理,这常常导致混淆。在函数中,经常是返回一个布尔值来表明函数运行的成功与否。 If SomeFunctionName() = True Then ' Function succeeded 但在调用一个存储过程时,却不能使用同样的方法,因为存储是用Execute方法运行的,同时返回一个记录集。 Set rsAuthors = cmdAuthors.Execute 如果得不到一个返回值,如何确定是否已正确执行存储过程?当发生错误时,会报告错误,这样就可使用前一章提供的错误处理代码来处理错误。但对于一些非致命的逻辑错误怎么办? 例如,考虑向employee表添加一个新职员的情形。你可能不想防止两个职员同名的情况,但想注明这个情况。那么,可以使用一个返回值以表明是否已有同名的职员存在。存储过程如下: CREATE PROCEDURE usp_AddEmployee @Emp_ID Char(9), @FName Varchar(20), @Minit Char(1), @LName Varchar(30), @Job_ID SmallInt, @Job_Lvl TinyInt, @Pub_ID Char(4), @Hire_Date Datetime AS BEGIN DECLARE @Exists Int -- Return value
-- See if an employee with the same name exists IF EXISTS(SELECT * FROM Employee WHERE FName = @FName AND MInit = @MInit AND LName = @LName) SELECT @Exists = 1 ELSE SELECT @Exists = 0
INSERT INTO Employee (emp_id, fname, minit, lname, job_id, job_lvl, pub_id, hire_date) VALUES (@Emp_Id, @FName, @MInit, @LName, @Job_ID, @Job_Lvl, @Pub_ID, @Hire_Date) RETURN @Exists END 该过程首先检查是否有同名的职员存在,并据此设定相应的变量Exists,若存在同名,就设为1,否则为0。然后将该职员加到表中,同时把Exists的值作为返回值返回。 注意尽管返回了一个值,但并未将其声明为存储过程的参数。 调用该过程的ASP代码如下: <!-- #INCLUDE FILE="../include/Connection.asp" --> <% Dim cmdEmployee Dim lngRecs Dim lngAdded
Set cmdEmployee = Server.CreateObject("ADODB.Command")
' Set the properties of the command With cmdEmployee .ActiveConnection = strConn .CommandText = "usp_AddEmployee" .CommandType = adCmdStoredProc
' Create the parameters ' Notice that the return value is the first parameter .Parameters.Append .CreateParameter ("RETURN_VALUE", adInteger, _ adParamReturnValue) .Parameters.Append .CreateParameter ("@Emp_id", adChar, adParamInput, 9) .Parameters.Append .CreateParameter ("@fname", adVarWChar, adParamInput, 20) .Parameters.Append .CreateParameter ("@minit", adChar, adParamInput, 1) .Parameters.Append .CreateParameter ("@lname", adVarWChar, adParamInput, 30) .Parameters.Append .CreateParameter ("@job_id", adSmallInt, adParamInput) .Parameters.Append .CreateParameter ("@job_lvl", adUnsignedTinyInt, adParamInput) .Parameters.Append .CreateParameter ("@pub_id", adChar, adParamInput, 4) .Parameters.Append .CreateParameter ("@hire_date", adDBTimeStamp, _ adParamInput, 8)
' Set the parameter values .Parameters("@Emp_id") = Request.Form("txtEmpID") .Parameters("@fname") = Request.Form("txtFirstName") .Parameters("@minit") = Request.Form("txtInitial") .Parameters("@lname") = Request.Form("txtLastName") .Parameters("@job_id") = Request.Form("lstJobs") .Parameters("@job_lvl") = Request.Form("txtJobLevel") .Parameters("@pub_id") = Request.Form("lstPublisher") .Parameters("@hire_date") = Request.Form("txtHireDate")
' Run the stored procedure .Execute lngRecs, , adExecuteNoRecords
' Extract the return value lngAdded = .Parameters("RETURN_VALUE") End With
Response.Write "New employee added.<P>" If lngAdded = 1 Then Response.Write "An employee with the same name already exists." End If
Set cmdEmployee = Nothing %> 需要重点注意,返回值应当作为集合中第一个参数被创建。即使返回值并不作为一个参数出现在存储过程中,总是Parameters集合中的第一个Parameters。 因此,特别强调一点: 存储过程的返回值必须声明为Parameters集合中第一个参数,同时参数的Direction值必须为adParamReturnValue。 使用返回值 现在定义一个初始窗体,如图9-3所示:
图9-3 初始窗体界面 按下Add Employee按钮会产生如图9-4所示的显示:
图9-4 按下Add Employee按钮后显示的界面 再添加同样的细节(ID号不同)会得到如图9-5所示的界面:
图9-5 添加细节后显示的界面 6. 更新参数 无需输入所有的参数细节,只需调用Refresh方法,就能让ADO完成更新。例如,假设已经创建了一个带有与前面例子相同的参数的过程usp_AddEmployee,并且没有改变运行的页面。 With cmdEmployee .ActiveConnection = strConn .CommandText = "usp_Addemployee" .CommandType = adCmdStoredProc 然后调用Refresh方法。 .Parameters.Refresh 这告诉ADO向数据存储请求每个参数的细节,并创建Parameters集合。然后可以为其赋值。 .Parameters("@Emp_Id") = Request.Form("txtEmpID") .Parameters("@FName") = Request.Form("txtFirstName") .Parameters("@MInit") = Request.Form("txtInitial") .Parameters("@LName") = Request.Form("txtLastName") .Parameters("@Job_ID") = Request.Form("lstJobs") .Parameters("@Job_Lvl") = Request.Form("txtJobLevel") .Parameters("@Pub_ID") = Request.Form("lstPublisher") .Parameters("@Hire_Date") = Request.Form("txtHireDate") 注意并不需要创建任何参数,包括返回值。 这似乎真是一条捷径,但应意识到这种方法也造成了性能上的损失,因为ADO必须向提供者查询以获得存储过程的参数细节。尽管如此,这种方法还是很有用的,尤其是在从参数中取出正确的值有困难的时候。 实际上,可以编写一个小实用程序作为开发工具使用,用来完成更新并建立Append语句,可以将其粘贴到自己的代码中。它看上去应该与图9-6所示的GenerateParameters.asp ASP页面类似。
图9-6 GenerateParameters.asp ASP页面 其代码相当简单。首先是包含连接符串和另一个ADOX常数文件。 <!-- #INCLUDE FILE="../Include/Connection.asp" --> <!-- #INCLUDE FILE="../Include/ADOX.asp" --> 接下来创建一个窗体,指定目标为PrintParameters.asp ASP页面。 <FORM NAME="Procedures" METHOD="post" ACTION="PrintParameters.asp"> Connection String:<BR> <TEXTAREA NAME="txtConnection" COLS="80" ROWS="5"> <% = strConn %> </TEXTAREA> <P> Stored Procedure:<BR> <SELECT NAME="lstProcedures"> 然后,使用ADOX从SQL Server中得到存储过程的列表,同时创建一个含有这些存储过程名字的列表框。 <% Dim catPubs Dim procProcedure
' Predefine the quote character strQuote = Chr(34) Set catPubs = Server.CreateObject("ADOX.Catalog")
catPubs.ActiveConnection = strConn
For Each procProcedure In catPubs.Procedures Response.Write "<OPTION VALUE=" & _ strQuote & procProcedure.Name & _ strQuote & ">" & procProcedure.Name Next
Set procProcedure = Nothing Set catPubs = Nothing %> </SELECT> <P> <INPUT TYPE="submit" VALUE="Print Paramaters"> </FORM> 这是一个简单的窗体,包括一个用于显示连接字符串的TEXTAREA控件和用于显示存储过程名称的SELECT控件。以前没有见过的是ADOX,ADOX是数据定义与安全的ADO扩展,可以用来访问数据存储的目录(或是元数据)。 本书不打算介绍ADOX的内容,但其十分简单。进一步的细节可参见《ADO Programmer's Reference》,Wrox出版社出版,2.1版或2.5版都行。 上面的例子使用了Procedures集合,这个集合包含数据存储中的所有存储过程的列表。按下PrintParameters按钮时,将得到图9-7所示的显示:
图9-7 按下Print Parameters按钮时显示的界面 可以简单地从这里拷贝参数行到代码中。在前面使用了一个以前从未见过的包含文件。该文件包含了几个将ADO常数(例如数据类型、参数方向等)转换为字符串值的函数: <!-- #INCLUDE FILE="../Include/Descriptions.asp" --> 接下来,定义一些变量,提取用户请求并创建Command对象。 <% Dim cmdProc Dim parP Dim strConnection Dim strProcedure Dim strQuote
' Get the connection and procedure name from the user strQuote = Chr(34) strConnection = Request.Form("txtConnection") strProcedure = Request.Form("lstProcedures")
'Update the user Response.Write "Connecting to <B>" & strConn
|