用 C# 编写 SQL Server 2005 托管自定义函数中,如何使用其他表数据
我用 C# 编写了一个自定义函数,其中需要读取另一个表的数据,并且枚举记录。我在其中用 SqlDataReader 和 SqlDataAdapter/DataTable 的方式都试过,报错(SqlDataAdapter 内部也是用 SqlDataReader 来操作)。
信息如下:
消息 6522,级别 16,状态 1,第 7 行
在执行用户定义例程或聚合 "GetSpanHours" 期间出现 .NET Framework 错误:
System.Data.SqlClient.SqlException: 在函数内的 'SET ON/OFF' 中对带副作用的或依赖于时间的运算符的使用无效。
System.Data.SqlClient.SqlException:
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.SqlInternalConnectionSmi.EventSink.DispatchMessages(Boolean ignoreNonFatalMessages)
at Microsoft.SqlServer.Server.SmiEventSink_Default.DispatchMessages(Boolean ignoreNonFatalMessages)
at Microsoft.SqlServer.Server.SmiEventSink_Default.DispatchMessages(Boolean ignoreNonFatalMessages)
at System.Data.SqlClient.SqlDataReaderSmi.InternalNextResult(Boolean ignoreNonFatalMessages)
at System.Data.SqlClient.SqlDataReaderSmi.NextResult()
at System.Data.SqlClient.SqlCommand.RunExecuteReaderSmi(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
at System.Data.SqlClient.SqlCommand.ExecuteReader()
at UserDefinedFunctions.GetWorkDays(SqlConnection conn, DateTime start, DateTime end)
at UserDefinedFunctions.GetSpanHours(SqlDateTime startTime, SqlDateTime endTime)
。
关键程序如下:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
public partial class UserDefinedFunctions
{
/// <summary>
/// 计算一段时间内占据的工作小时数
/// </summary>
/// <param name="start">开始时间</param>
/// <param name="end">结束时间</param>
/// <returns></returns>
[SqlFunction(DataAccess=DataAccessKind.Read)]
public static SqlInt32 GetSpanHours(SqlDateTime startTime, SqlDateTime endTime)
{
DateTime start = AdjustStartTime(startTime.Value);
DateTime end = AdjustEndTime(endTime.Value);
bool addStart; // 第一天是否工作日?
bool addEnd; // 最后一天是否工作日?
int workdayCount;
using (SqlConnection conn = new SqlConnection("Context Connection=true"))
{
conn.Open();
SqlDataReader workdays = GetWorkDays(conn, startTime.Value, startTime.Value);
GetIsStartOrEndWorkDay(workdays, start, end, out addStart, out addEnd, out workdayCount);
}
int hours = CalculateSpanHours(start, end, addStart, addEnd, workdayCount);
return new SqlInt32(hours);
}
private static SqlDataReader GetWorkDays(SqlConnection conn, DateTime start, DateTime end)
{
SqlCommand cmd = conn.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "usp_GetWorkDays";
cmd.Parameters.AddWithValue("@start", start);
cmd.Parameters.AddWithValue("@end", end);
return cmd.ExecuteReader();
}
// ....
}