SQL查询在SSMS中返回值,在DataTable中该值为DBNull

时间:2018-07-09 05:27:30

标签: c# sql-server tsql ado.net

我有一个查询,该查询是我在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)。

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

尝试从其他sys表中选择。例如。 :

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]没有长度,表示它尽可能大。如果它将为同一SP返回几行,则需要在应用程序中添加另一个循环并连接字符串。

让我知道它是否有效

答案 1 :(得分:0)

事实证明,@ DaveBrown的回答正确:这是一个权限问题,尽管它没有按照我认为的方式运行。

我在查询中添加了LEN([definition])。当时的想法是,如果这是ADO.Net中的问题,需要提取24,000个字符的sproc定义,我仍然会得到该定义的字符数。如果返回NULL值,则说明SQL Server中发生了这种情况。

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 Server在尝试查询定义而不返回null时会引发错误。