由于未使用的变量,CLR在首次使用时失败

时间:2014-02-04 20:34:49

标签: sql sql-server sql-server-2012 sqlclr

我遇到一个完全未使用的变量导致错误的情况。删除未使用的变量声明会清除错误。清除后,错误将保持清除(即使未使用的变量已恢复),直到SQL Server重新启动,此时它将返回。

我已经定义了一个CLR函数和一个表值UDF。我可以使用这个测试用例代码调用CLR:

Declare @name_does_not_matter Table (any_column_name int);

Select dbo.MapTesseractUris(
    N'<a href="tesseract:2">map this uri</a>',
    N'localhost:6313');

这样做会导致此错误:

A .NET Framework error occurred during execution of user-defined routine or aggregate "MapTesseractUris": 
System.Data.SqlClient.SqlException: 
System.Data.SqlClient.SqlException: 
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.SqlCommand.SetUpSmiRequest(SqlInternalConnectionSmi innerConnection)
   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, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
   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 Tesseract.Database.TesseractUri.MapPageIdsToUrls(IEnumerable`1 pageIds, String forDomain)
   at Tesseract.Database.TesseractUri.MapTesseractUris(String html, String forDomain)

错误发生在我的代码中CLR调用UDF的位置。直接调用UDF不会导致错误。

但是,如果我使用此代码调用CLR,我会得到正确的预期结果:

Select dbo.MapTesseractUris(
    N'<a href="tesseract:2">map this uri</a>',
    N'localhost:6313');

一旦我成功执行,进一步的执行将始终正常运行。我可以恢复丢失的Declare语句,但不会出错。我可以改变输入参数而不是错误。

我可以通过重新启动SQL Server或删除并重新部署整个数据库来导致错误返回。

如果不明显,@name_does_not_matter表变量不会在任何地方使用。这必须是导致问题的表变量(Declare @name_does_not_matter int不会导致问题)。

导致这种情况的原因是什么?

如何解决这个问题,而不是每次SQL Server重新启动时都执行“修复”SQL?

更新

以下是Tesseract.Database.TesseractUri.MapPageIdsToUrls的请求代码:

private static IDictionary<int, string> MapPageIdsToUrls(
    IEnumerable<int> pageIds,
    string forDomain)
{
    using (var db = new SqlConnection("context connection=true")) {
        db.Open();

        using (var cmd = db.CreateCommand()) {
            cmd.CommandType = CommandType.Text;
            cmd.CommandText = @"
                Select [Id], [Url]
                From [dbo].[ResolvePageUrls](@pageIds, @domain)";

            var p = cmd.Parameters.AddWithValue(
                "@pageIds",
                CreateDataRecords(pageIds));

            p.SqlDbType = SqlDbType.Structured;
            p.TypeName = "dbo.IntTable";

            cmd.Parameters
                .Add("@domain", SqlDbType.NVarChar, 252)
                .Value = forDomain;

            using (var reader = cmd.ExecuteReader()) {
                return reader.OfType<IDataRecord>()
                    .Select(row => Tuple.Create(
                        row.GetInt32(0),
                        row.GetValue(1) as string))
                    .ToDictionary(t => t.Item1, t => t.Item2);
            }
        }
    }
}

private static IEnumerable<SqlDataRecord> CreateDataRecords(
    IEnumerable<int> ids)
{
    var metaData = new[] { new SqlMetaData("Value", SqlDbType.Int) };
    var record = new SqlDataRecord(metaData);
    foreach (var id in ids.Distinct()) {
        record.SetInt32(0, id);
        yield return record;
    }
}

0 个答案:

没有答案