.net - 从查询中获取表架构

标签 .net sql ado.net metadata

根据 MSDN , SqlDataReader.GetSchemaTable 返回所执行查询的列元数据。我想知道是否有类似的方法可以为给定的查询提供表元数据?我的意思是涉及哪些表以及它有哪些别名。

在我的应用程序中,我收到查询,并且需要以编程方式附加 where 子句。使用GetSchemaTable(),我可以获得列元数据及其所属的表。但即使表有别名,它仍然返回真实的表名。有没有办法获取该表的别名?

以下代码显示获取列元数据。

const string connectionString = "your_connection_string";
string sql = "select c.id as s,c.firstname from contact as c";

using(SqlConnection connection = new SqlConnection(connectionString))
using(SqlCommand command = new SqlCommand(sql, connection))
{
    connection.Open();
    SqlDataReader reader = command.ExecuteReader(CommandBehavior.KeyInfo);
    DataTable schema = reader.GetSchemaTable();
    foreach (DataRow row in schema.Rows)
    {
        foreach (DataColumn column in schema.Columns)
        {
            Console.WriteLine(column.ColumnName + " = " + row[column]);
        }
        Console.WriteLine("----------------------------------------");
    }
    Console.Read();
}

这将正确地为我提供列的详细信息。但是,当我看到 Id 列的 BaseTableName 时,它给出的是 contact 而不是别名 c。有没有办法从上面的查询中获取表架构和别名?

任何帮助都会很棒!

编辑

虽然我可以使用 Rob 建议的执行计划,但我会很感激任何替代的简单方法。

回答tomekszpakowicz的问题

Are you (or your application) source of the query in question? In that case you should know the aliases.

我不是查询的作者。我们有一个系统,用户可以在其中输入查询。我们使用我上面解释的方法从中构建列。这些详细信息将被保留,其他用户可以使用它,例如添加新条件等。因此,我们需要根据我们拥有的信息动态构建 SQL。因此,当列有别名并且我们没有获取别名时,构造的 where 子句将无效。

谢谢

最佳答案

简短回答

这行不通。根据设计,您无法从结果模式中获取表别名。并且您不能依赖能够从查询执行计划中获取它们。

长答案

当您获得 SQL 查询的结果时,查询已经被解析、验证、优化、编译成某种内部表示并执行。别名是查询“源代码”的一部分,通常会在步骤 1 和 2 附近的某个地方丢失。

执行查询后,唯一可以被视为表的东西是a)真实的物理表和b)返回的数据被视为单个匿名表。两者之间的一切都可以转化或完全优化。

如果要求 DBMS 保留别名,那么优化复杂查询实际上是不可能的。

可能的解决方案

我建议重述一个问题:

  1. 您(或您的应用程序)是相关查询的来源吗?在这种情况下,您应该知道别名。

  2. 如果您收到其他人提供的查询...嗯...这取决于您添加原因的原因。

    • 在最坏的情况下,您必须自己解析查询。

    • 在最好的情况下,您可以让他们访问 View 而不是真实的表,并在 View 中放置 where 子句。

<小时/>

简单而丑陋的解决方案

如果我正确理解您的要求:

  • 用户 A 在您的程序中输入查询。

  • 用户 B 可以运行它(但无法编辑它)并查看返回的数据。 此外,她可以使用您提供的某种小部件根据返回的列添加过滤器。

  • 您不想在应用程序内部应用过滤器,而是将它们添加到查询中,以避免从数据库中获取不必要的数据。

在这种情况下:

  • 当 A 编辑查询时,尝试运行它并收集返回列的元数据。 如果 ColumnName 不唯一,请向作者投诉。 通过查询存储元数据。

  • 当 B 添加过滤器(基于查询元数据)时,存储两个列名称 和条件。

  • 执行时:

    • 检查过滤列是否仍然有效(A 可能已更改查询)。 如果不删除无效过滤器和/或通知 B.

    • 执行查询,如下所示:

       select *
       from ({query entered by A}) x
       where x.Column1 op1 Value1
           and x.Column2 op2 Value2
      

如果您想优雅地处理数据库架构更改,您需要添加一些额外的检查以确保元数据与查询实际返回的内容一致。

安全说明

您的程序将把用户 A 编写的查询直接传递到数据库。 至关重要的是,您使用数据库连接来执行此操作的权限不超过 A 的数据库权限。 否则,您将要求基于 SQL 注入(inject)的漏洞利用。

推论

如果出于安全原因,用户 A 无权直接访问数据库,则无法使用上述解决方案。

在这种情况下,保证其安全的唯一方法是确保您的应用程序理解 100% 的查询,这意味着在您的程序中解析查询并仅允许您认为安全的操作。

关于.net - 从查询中获取表架构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3059126/

相关文章:

c# - 如何验证 COM 对象可以在另一个用户下实例化?

c# - 在 WinForms 桌面应用程序中使用 jQuery?

php - 如何显示数据库中存储的所有图像

c# - 无法将值 NULL 插入 EF 6.1.3 中的列

c# - 使用哪个通用集合?

sql - 如何基于两个不同的列进行 ORDER BY

python - 从 sql 字符串中提取表名、列等参数

c# - 为什么我的 SqlCommand 返回一个字符串,而它应该是一个 int?

c# - 如何检查我的数据库中是否已存在一个值并显示验证消息

c# - 如何记录执行的sql语句