我正在尝试重用一些找到here的代码。使用c#添加一个新的(如下所示)似乎没问题。
然而,当我去发布数据库时,代码生成器似乎不识别IEnumerable类型并最终产生错误。下面生成的代码中的实际错误(AS附近的语法错误)很明显,所以我的问题是如何让SSDT生成正确的代码并避免错误原因?(我假设我可以手动添加CLR,但是,我更喜欢从SSDT做的所有事情)
目前生成:
CREATE FUNCTION [dbo].[RegExMatches] (@sourceString [nvarchar](4000), @pattern [nvarchar](4000))
RETURNS /* Error: Unsupported type. */
AS EXTERNAL NAME [CampaignStrategyStaging].[SQLRegEx].[RegExMatches];
应该生成如下内容:
CREATE FUNCTION [dbo].[RegExMatches] (@sourceString [nvarchar](4000), @pattern [nvarchar](4000))
RETURNS TABLE (
[rowId] int, --RowId each row as it`s ID
[matchId] int, --ID of particular match (starts from 1)
[groupId] int, --ID of particular group in RegEx match (GroupID = 0) represents a complete match
[value] nvarchar(4000) --value of the group
) WITH EXECUTE AS CALLER
AS EXTERNAL NAME [CampaignStrategyStaging].[SQLRegEx].[RegExMatches];
CLR的C#:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Text.RegularExpressions;
using System.Collections;
public class SQLRegEx
{
private class RegExRow
{
/// <summary>
/// Private class for passing matches of the RegExMatches to the FillRow method
/// </summary>
/// <param name=”rowId”>ID of the Row</param>
/// <param name=”matchId”>ID of the Match</param>
/// <param name=”groupID”>ID of the Group within the Match</param>
/// <param name=”value”>Value of the particular group</param>
public RegExRow(int rowId, int matchId, int groupID, string value)
{
RowId = rowId;
MatchId = matchId;
GroupID = groupID;
Value = value;
}
public int RowId;
public int MatchId;
public int GroupID;
public string Value;
}
/// <summary>
/// Applies Regular Expression on the Source string and returns value of particular group from withing a specified match
/// </summary>
/// <param name=”sourceString”>Source string on which the regular expression should be applied</param>
/// <param name=”pattern”>Regular Expression pattern</param>
/// <param name=”matchId”>ID of the Match to be returned 1 inex-based</param>
/// <param name=”groupId”>ID of the group from within a match to return. GroupID 0 returns complete match</param>
/// <returns>Value of the Group from within a Match</returns>
[SqlFunction(IsDeterministic=true)]
public static SqlChars RegExMatch(string sourceString, string pattern, int matchId, int groupId)
{
Match m = null;
Regex r = new Regex(pattern, RegexOptions.Compiled);
if (matchId == 1)
{
m = r.Match(sourceString);
}
else if (matchId > 1)
{
MatchCollection mc = r.Matches(sourceString);
if (mc!=null && mc.Count > matchId-1)
{
m = mc[matchId-1];
}
else
{
m= null;
}
///m = mc != null && mc.Count > matchId – 1 ? mc[matchId - 1] : null;
}
return m != null && m.Groups.Count > groupId ? new SqlChars(m.Groups[groupId].Value) : SqlChars.Null;
}
/// <summary>
/// Applies Regular Expression o the Source strings and return all matches and groups
/// </summary>
/// <param name=”sourceString”>Source string on which the regular expression should be applied</param>
/// <param name=”pattern”>Regular Expression pattern</param>
/// <returns>Returns list of RegExRows representing the group value</returns>
[SqlFunction(FillRowMethodName = "FillRegExRow")]
public static IEnumerable RegExMatches(string sourceString, string pattern)
{
Regex r = new Regex(pattern, RegexOptions.Compiled);
int rowId = 0;
int matchId = 0;
foreach (Match m in r.Matches(sourceString))
{
matchId++;
for (int i = 0; i < m.Groups.Count; i++)
{
yield return new RegExRow(++rowId, matchId, i, m.Groups[i].Value);
}
}
}
/// <summary>
/// FillRow method to populate the output table
/// </summary>
/// <param name=”obj”>RegExRow passed as object</param>
/// <param name=”rowId”>ID or the returned row</param>
/// <param name=”matchId”>ID of returned Match</param>
/// <param name=”groupID”>ID of group in the Match</param>
/// <param name=”value”>Value of the Group</param>
public static void FillRegExRow(Object obj, out int rowId, out int matchId, out int groupID, out SqlChars value)
{
RegExRow r = (RegExRow)obj;
rowId = r.RowId;
matchId = r.MatchId;
groupID = r.GroupID;
value = new SqlChars(r.Value);
}
}
答案 0 :(得分:3)
在一位同事的帮助下,我发现CLR需要进行两项更改:
SQLFunction []声明需要包含TableDefinition 参数如here上的示例所示。 (代码如下所示)
[SqlFunction(FillRowMethodName = "FillRegExRow",
TableDefinition = "[rowId] int,[matchId] int,[groupId] int, [value] nvarchar(4000)")]
public static IEnumerable RegExMatches(string sourceString, string pattern)
RegExRow.RegExRow中的int数据类型已更改为SqlInt32。 (这可能不是解决我原始问题中的问题所必需的。)
所以整体代码改为:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Text.RegularExpressions;
using System.Collections;
public class SQLRegEx
{
private class RegExRow
{
/// <summary>
/// Private class for passing matches of the RegExMatches to the FillRow method
/// </summary>
/// <param name=”rowId”>ID of the Row</param>
/// <param name=”matchId”>ID of the Match</param>
/// <param name=”groupID”>ID of the Group within the Match</param>
/// <param name=”value”>Value of the particular group</param>
public RegExRow(SqlInt32 rowId, SqlInt32 matchId, SqlInt32 groupID, string value)
{
RowId = rowId;
MatchId = matchId;
GroupID = groupID;
Value = value;
}
public SqlInt32 RowId;
public SqlInt32 MatchId;
public SqlInt32 GroupID;
public string Value;
}
/// <summary>
/// Applies Regular Expression on the Source string and returns value of particular group from withing a specified match
/// </summary>
/// <param name=”sourceString”>Source string on which the regular expression should be applied</param>
/// <param name=”pattern”>Regular Expression pattern</param>
/// <param name=”matchId”>ID of the Match to be returned 1 inex-based</param>
/// <param name=”groupId”>ID of the group from within a match to return. GroupID 0 returns complete match</param>
/// <returns>Value of the Group from within a Match</returns>
[SqlFunction(IsDeterministic=true)]
public static SqlChars RegExMatch(string sourceString, string pattern, int matchId, int groupId)
{
Match m = null;
Regex r = new Regex(pattern, RegexOptions.Compiled);
if (matchId == 1)
{
m = r.Match(sourceString);
}
else if (matchId > 1)
{
MatchCollection mc = r.Matches(sourceString);
if (mc!=null && mc.Count > matchId-1)
{
m = mc[matchId-1];
}
else
{
m= null;
}
///m = mc != null && mc.Count > matchId – 1 ? mc[matchId - 1] : null;
}
return m != null && m.Groups.Count > groupId ? new SqlChars(m.Groups[groupId].Value) : SqlChars.Null;
}
/// <summary>
/// Applies Regular Expression o the Source strings and return all matches and groups
/// </summary>
/// <param name=”sourceString”>Source string on which the regular expression should be applied</param>
/// <param name=”pattern”>Regular Expression pattern</param>
/// <returns>Returns list of RegExRows representing the group value</returns>
///
[SqlFunction(FillRowMethodName = "FillRegExRow",
TableDefinition = "rowId int,[matchId] int,[groupId] int, [value] nvarchar(4000)")]
public static IEnumerable RegExMatches(string sourceString, string pattern)
{
Regex r = new Regex(pattern, RegexOptions.Compiled);
int rowId = 0;
int matchId = 0;
foreach (Match m in r.Matches(sourceString))
{
matchId++;
for (int i = 0; i < m.Groups.Count; i++)
{
++rowId;
yield return new RegExRow(rowId, matchId, i, m.Groups[i].Value);
}
}
}
/// <summary>
/// FillRow method to populate the output table
/// </summary>
/// <param name=”obj”>RegExRow passed as object</param>
/// <param name=”rowId”>ID or the returned row</param>
/// <param name=”matchId”>ID of returned Match</param>
/// <param name=”groupID”>ID of group in the Match</param>
/// <param name=”value”>Value of the Group</param>
public static void FillRegExRow(Object obj, out SqlInt32 rowId, out SqlInt32 matchId, out SqlInt32 groupID, out SqlChars value)
{
RegExRow r = (RegExRow)obj;
rowId = r.RowId;
matchId = r.MatchId;
groupID = r.GroupID;
value = new SqlChars(r.Value);
}
}