VS 2012 SSDT构建CLR,IEnumerable生成语法失败

时间:2014-07-28 18:29:23

标签: 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);
}

}

1 个答案:

答案 0 :(得分:3)

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

  1. SQLFunction []声明需要包含TableDefinition 参数如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。 (这可能不是解决我原始问题中的问题所必需的。)

  3. 所以整体代码改为:

    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);
    }
    

    }