sql-server - VS 2012 SSDT 构建 CLR,IEnumerable 生成的语法失败

标签 sql-server visual-studio-2012 clr ienumerable sql-server-data-tools

我正在尝试重用发现的一些代码 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);
}

}

最佳答案

在同事的帮助下,我发现 CLR 需要进行两处更改:

  1. 包含 TableDefinition 所需的 SQLFunction[] 声明 参数如 here 上的示例所示。 (代码如下)

    [SqlFunction(FillRowMethodName = "FillRegExRow",
    TableDefinition = "[rowId] int,[matchId] int,[groupId] int, [value] nvarchar(4000)")]
    public static IEnumerable RegExMatches(string sourceString, string pattern)
    
  2. 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);
}

}

关于sql-server - VS 2012 SSDT 构建 CLR,IEnumerable 生成的语法失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25001853/

相关文章:

SQL Server : How to change name in a view?

sql-server - 过滤索引寻找 `is NULL` 条件并扫描相反的条件

c++ - Visual Studio 2012 :error LNK1117: syntax error in option 'MAPINFO:LINES'

.net 运行时 - Silverlight 运行时 =?

java - 通配符转义 JPA 规范

visual-studio-2012 - Visual Studio、Knockout 和 Razor : unwanted white space added

sql-server - SQL Server数据库项目: Publish decide when to recreate a table?如何

c# - VC++属于托管类还是非托管类?

python - 导入 someModule,而不是 clr.AddReferenceToFile ("someModule")?

sql-server - 在不同的数据库上下文下执行存储过程?