SQL查询returnsSSMS中的值,DataTable中的值为DBNull

SQL query returns value in SSMS, value is DBNull in DataTable

我在 SQL Server Management Studio 中创建了这个查询,用于获取数据库中存储过程的定义。

Select [definition], [uses_ansi_nulls], [uses_quoted_identifier], 
    [is_schema_bound], [uses_database_collation], [is_recompiled], 
    [null_on_null_input], [execute_as_principal_id], 
    [uses_native_compilation]
From [sys].[sql_modules]
Where [object_id] = @object_Id

在 SSMS 中,如果我 Declare @object_Id int = <storedproc's object_id> 和 运行 它,我会取回定义值(SQL 代码)和各种其他属性。

在我的应用程序中,我有这段代码。以上 SQL 查询是项目的资源。

static void RenderDefinition(int objectId, XmlElement parentElement)
{
    var dt = new DataTable();

    using (var da = new SqlDataAdapter(Resources.Commands.GetDefinition, connectionString))
    {
        da.SelectCommand.Parameters.Add("@object_Id", SqlDbType.Int).Value = objectId;
        da.Fill(dt);
    }

    var row = dt.Rows[0];

    // Create object element
    var e = parentElement.AppendChild(parentElement.OwnerDocument.CreateElement("definition")) as XmlElement;

    foreach (DataColumn col in dt.Columns)
    {
        var value = row.ToXmlString(col);
        if (string.IsNullOrWhiteSpace(value)) continue;

        if (col.ColumnName == "definition")
        {
            // The SQL code
            e.InnerText = value; // <-- Value is always DBNull, never the actual value
        }
        else
        {
            // Other defining attributes
            e.SetAttribute(col.ColumnName, value);
        }
    }
}

这会生成以下内容 XML:

<definition uses_ansi_nulls="true" uses_quoted_identifier="true" is_schema_bound="false" uses_database_collation="false" is_recompiled="false" null_on_null_input="false" uses_native_compilation="false"></definition>

我已经按原样尝试了查询。我试过将定义列转换为 VARCHAR(MAX) 和 VARCHAR(8000)。

有什么想法吗?

尝试从不同的系统中选择 table。例如。 :

SELECT DISTINCT SCHEMA_NAME(o.schema_id),o.name,c.[text]
FROM syscomments AS c
INNER JOIN sys.objects AS o ON c.id = o.[object_id]
INNER JOIN sys.schemas AS s ON o.schema_id = s.schema_id
WHERE object_id = <your id>

另一个可能对您有帮助的查询:

SELECT so.[name],  m.[definition]
FROM sys.objects as so
inner join sys.sql_modules as m on m.object_id = so.object_id
WHERE so.[type] = 'P' AND so.object_id = <your id>;

这里的 m.[definition] 没有长度,意味着它尽可能大。如果它将 return 同一 SP 的多行,您将需要向您的应用程序添加另一个循环并连接字符串。

如果有效请告诉我

事实证明,@DaveBrown 的答案是正确的:这是一个权限问题,尽管它的行为方式与我想象的不同。

我在查询中添加了 LEN([definition])。我的想法是,如果 ADO.Net 提取 24,000 个字符的存储过程定义时出现问题,我仍然会得到定义的字符数。如果它 return 编辑了一个 NULL 值,那么它是在 SQL 服务器中发生的事情。

Select [definition], LEN([definition]) [definition_length], [uses_ansi_nulls], [uses_quoted_identifier], 
    [is_schema_bound], [uses_database_collation], [is_recompiled], 
    [null_on_null_input], [execute_as_principal_id], 
    [uses_native_compilation]
From [sys].[sql_modules]
Where [object_id] = @object_Id

当我在断点处停止时,LEN([definition]) 为空。

事实证明,一个为了保护罪犯而保持匿名的人在我们想要记录的环境中没有与她在初始环境中相同的权限。该代码在我对存储过程和其他其他模块拥有作者权限的环境之一中工作。

这最终归结为由于权限导致的意外行为。我希望 SQL 服务器在尝试查询定义时引发错误而不是 return null.