我有一个 C# (.NET Framework 4.7.2) 脚本来执行一些跟踪代码的自定义读取,我试图用它来创建 SQL (V14.0.3445.2) 表值函数。 C# FillRow 方法如下所示:
public partial class UserDefinedFunctions
{
[SqlFunction(DataAccess = DataAccessKind.Read, FillRowMethodName = "Read_Trace",
TableDefinition =
" Site NVARCHAR(3)" +
",Line TINYINT" +
",Shift NVARCHAR(2)" +
",ProductionDate DATETIME2(0)" +
",ProductionTime NVARCHAR(5)" +
",DayName NVARCHAR(9)" +
",Perfect_Trace BIT" +
",NWFGenerated_Trace BIT" +
",Altered_Trace BIT")]
public static IEnumerable Read_Trace([SqlFacet(MaxSize = 255)] SqlChars customer, [SqlFacet(MaxSize = 255)] SqlChars trace)
{
var trc = trace.ToString();
RegexList regexList = GetRegexList(customer.ToString(), trace.ToString());
return new List<TraceContents>
{
new TraceContents
{
Site = GetValue(regexList.Site_Regex, trc),
Line = SqlInt16.Parse(new string(GetValue(regexList.Line_Regex, trc).Where(char.IsNumber).ToArray())),
Shift = GetValue(regexList.Shift_Regex, trc),
ProductionDate = JulianToDate(GetValue(regexList.Date_Regex, trc)),
ProductionTime = GetValue(regexList.Time_Regex, trc),
DayName = GetValue(regexList.Day_Regex, trc),
Perfect_Trace = regexList.Perfect_Trace,
NWFGenerated_Trace = regexList.NWFGenerated_Trace,
Altered_Trace = regexList.Altered_Trace
}
};
}
我有以下 SQL 脚本可以将其变成一个函数:
DROP ASSEMBLY if exists CLR_Functions;
CREATE ASSEMBLY CLR_Functions
FROM 'C:\Temp\Functions.dll'
GO
CREATE FUNCTION fn_ReadTraceCode(@InvoiceAccount NVARCHAR(255), @Trace NVARCHAR(255)) RETURNS
TABLE (
[Site] NVARCHAR(3)
,[Line] TINYINT
,[Shift] NVARCHAR(2)
,[ProductionDate] DATETIME2(0)
,[ProductionTime] NVARCHAR(5)
,[DayName] NVARCHAR(9)
,[Perfect_Trace] BIT
,[NWFGenerated_Trace] BIT
,[Altered_Trace] BIT)
AS EXTERNAL NAME CLR_Functions.UserDefinedFunctions.Read_Trace
GO
这两个脚本的参数数量匹配,我认为这是要求,但是当我运行 SQL 脚本时,出现以下错误:
消息 6208,级别 16,状态 1,过程 fn_ReadTraceCode,第 2 行 [批次 开始行 4] CREATE FUNCTION 失败,因为参数计数为 FillRow 方法应该比 SQL 声明多 1 表值 CLR 函数。
我不明白我做错了什么 - 我已经按照分步指南进行操作(如this),但没有找到任何有关所需附加参数的信息,事实上,在此之前曾经创建过一个 CLR 函数似乎需要一个额外的参数...这个问题的唯一在线答案是指函数的 return 列之间存在真正不匹配的事件,这加剧了我的困惑。
你能帮助我停止出现错误,以便我的函数可以编译吗?如果需要,我可以发布完整的代码,但我认为问题出在上面列出的 FillRow 方法上。
您的代码根本不符合 SQLCLR 的预期。如果您查看文档,您需要两个函数:一个用于返回
IEnumerable
,另一个用于填充行并具有一堆out
参数来执行此操作。
[SqlFunction(
DataAccess = DataAccessKind.Read,
FillRowMethodName = nameof(Read_Trace_Fill),
TableDefinition =
" Site NVARCHAR(3)" +
",Line TINYINT" +
",Shift NVARCHAR(2)" +
",ProductionDate DATETIME2(0)" +
",ProductionTime NVARCHAR(5)" +
",DayName NVARCHAR(9)" +
",Perfect_Trace BIT" +
",NWFGenerated_Trace BIT" +
",Altered_Trace BIT")]
public static IEnumerable Read_Trace([SqlFacet(MaxSize = 255)] SqlChars customer, [SqlFacet(MaxSize = 255)] SqlChars trace)
{
var trc = trace.ToString();
RegexList regexList = GetRegexList(customer.ToString(), trace.ToString());
return new List<TraceContents>
{
new TraceContents
{
Site = GetValue(regexList.Site_Regex, trc),
Line = SqlInt16.Parse(new string(GetValue(regexList.Line_Regex, trc).Where(char.IsNumber).ToArray())),
Shift = GetValue(regexList.Shift_Regex, trc),
ProductionDate = JulianToDate(GetValue(regexList.Date_Regex, trc)),
ProductionTime = GetValue(regexList.Time_Regex, trc),
DayName = GetValue(regexList.Day_Regex, trc),
Perfect_Trace = regexList.Perfect_Trace,
NWFGenerated_Trace = regexList.NWFGenerated_Trace,
Altered_Trace = regexList.Altered_Trace
}
};
}
public static void Read_Trace_Fill(
Object traceObj,
out string Site,
out byte Line,
out string Shift,
out DateTime? ProductionDate,
out string ProductionTime,
out string DayName,
out bool Perfect_Trace,
out bool NWFGenerated_Trace,
out bool Altered_Trace
)
{
var trace = (TraceContents)traceObj;
Site = trace.Site;
Line = trace.Line;
Shift = trace.Shift;
ProductionDate = trace.ProductionDate;
ProductionTime = trace.ProductionTime;
DayName = trace.DayName;
Perfect_Trace = trace.Perfect_Trace;
NWFGenerated_Trace = trace.NWFGenerated_Trace;
Altered_Trace = trace.Altered_Trace;
}
如果结果很大(即多行),那么您最终会将整个结果存储在内存中。理想情况下,您应该使用
yield return
创建流式 IEnumerable
。在这种情况下,您似乎只返回一行。