【问题标题】:SQL query returns value in SSMS, value is DBNull in DataTableSQL查询返回SSMS中的值,DataTable中的值为DBNull
【发布时间】:2018-12-16 17:35:47
【问题描述】:

我在 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)。

有什么想法吗?

【问题讨论】:

  • bigint 不是 int...
  • @ZoharPeled 感谢您的捕获,尽管它不会改变行为,因为它已本地化为 SSMS。
  • 调试时,dt.Rows.Count返回什么?
  • Resources.Commands.GetDefinition的值是多少?
  • 可能是权限问题,虽然不能确定。查看docs.microsoft.com/en-us/sql/relational-databases/…

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


【解决方案1】:

尝试从不同的 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 返回多行,您将需要向您的应用程序添加另一个循环并连接字符串。

让我知道它是否有效

【讨论】:

  • 这在 SSMS 中运行时没有返回定义的全文,缺少部分。
  • 如果过程很大,它可能会返回两行,SP开头和SP结尾...检查它是否在C#代码中工作
  • 对于我的开发场景,我使用了一个大存储过程,有超过 450 行和超过 24,000 个字符,它是一个怪物。此查询返回 7 条记录,不到 1,800 个字符。
【解决方案2】:

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

我在查询中添加了 LEN([definition])。想法是,如果在 ADO.Net 中拉下 24,000 个字符的存储过程定义存在问题,我仍然会得到定义的字符数。如果它返回一个 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 时引发错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-03
    • 1970-01-01
    • 1970-01-01
    • 2022-01-01
    • 2014-04-27
    • 1970-01-01
    • 2020-12-19
    • 1970-01-01
    相关资源
    最近更新 更多