【问题标题】:Get value of first column without knowing name在不知道名称的情况下获取第一列的值
【发布时间】:2016-11-10 02:21:48
【问题描述】:

Column Number rather than Column Name 类似,但我相信它是不同的,因为那是针对未命名的列,而我的列是命名的,我只是不知道提前的名称。

首先,一些背景。我正在创建一个将查询及其参数作为参数的方法,然后运行查询(使用 Dapper)并检查第一行、第一列的值是 1 还是 0。它旨在用作通用验证器数据库。

例如,用户可以输入一个查询,如果某个表中存在某个值,则该查询在唯一行的唯一列中返回 1,否则返回 0。此方法的使用范围非常广泛,并且大部分精力都放在编写查询的用户身上(我还应该澄清一下,在这种情况下,“用户”始终是另一个开发人员,并且使用是在调用此方法的代码中完成的,不是在表单输入上)。

我想查询我的数据库并在不知道列名的情况下提前获取第一行、第一列的值。理想情况下(虽然我不确定这是否可能在 Dapper 调用中),我还希望 要求 结果中只有一行和一列。当我四处寻找时,我的初始解决方案基于this 帖子的第一个答案,但发现要使其工作,我需要知道列的名称:

var dict = connection.Query(query, parameters).ToDictionary(row => (string)row.VALUE);
if(dict.ElementAt(0).Value != 1){
    //do stuff
}

我想只添加一个要求,即用户添加一个别名,该别名将第一列命名为某个常量值(在本例中为 VALUE),但我宁愿不把负担放在我的用户身上可能。

最终我的核心问题是:如何在不知道列名的情况下使用 Dapper 获取数据库中命名列的值? 有人有什么想法吗?

【问题讨论】:

  • 如何定义结果集中的“第一”行?您的所有查询都保证有一个确定性的 ORDER BY 子句吗?
  • @mathguy 最终我希望查询只返回一行;这种方法故意非常广泛。正如我所说,此方法旨在成为数据库数据的通用验证器;因此,当正确使用时,查询将只有一个结果行。如果有不止一行,则查询无效,我可以检查此问题范围之外的内容。这种方法的工作负担在于用户编写查询,这是有意的。如果可能的话,我只是不想要求他们为他们的专栏命名。

标签: c# .net oracle dapper


【解决方案1】:

使用 Tortuga 链

var result = DataSource.Sql(query, parameters).ToInt32().Execute();

我还想要求结果中只有一行一列

默认情况下,Chain 使用 DbCommand.ExecuteScalar。这将返回第一行的第一列,忽略其他所有内容。要添加该限制,我会这样做:

var result = DataSource.Sql(query, parameters).ToInt32List().Execute().Single;

另一个选项是更改生成 SQL 的方式。例如,

var filterObject = new {ColumnA = 1, ColumnB = "X", ColumnC = 17};
var result = DataSource.From(tableName, filterObject).ToInt32(columnName).Execute();

这样做的好处是不受 SQL 注入攻击(这可能是您关心的问题),并确保您的 SQL 在执行之前只返回一列

【讨论】:

    【解决方案2】:

    我已经成功地通过使用 int 作为通用 Query 方法中的类型:

    int value = conn.Query<int>(sql,
    commandType: CommandType.StoredProcedure).FirstOrDefault();
    

    注意 FirstOrDefault 方法的使用。所以你从数据库中得到 0 或任何值。

    【讨论】:

    • 确实是这样。或 ExecuteScalar。
    • 只是为了确保我理解,在这种情况下,如果查询由于某种原因返回第一行、第一列值不是整数的结果,value 将被设置为 0?
    • 是的,我相信是的。当然,如果您不知道返回的类型,您可以返回一个对象并检查类型的代码。虽然不是最好的主意。
    • ExecuteScalar 可能更快,但您无法确保只有一行/列。
    • 作为对 Chris H. 上述问题的更新,当我返回“null”值时,Dapper 抛出“未设置对象引用”错误。所以我不得不将int更改为int?并在设置之前确保它有一个值。
    【解决方案3】:

    最简单的做法是确保 SQL 命令始终通过别名返回相同的列名。然后您的 C# 代码就可以使用该别名。

    【讨论】:

    • 问题是我想取用户输入的通用SQL命令,所以不能保证会使用别名。我在代码块之后提到了这一点。
    • 那你真的没有使用 Dapper 或任何其他 ORM 的业务! ORM 旨在将您的代码从人工生成的 SQL 语句中抽象出来。很棒的工具,但你误用了它。
    • 此方法仅供最熟悉 dapper 的其他开发人员在内部使用,并且可能希望在其查询中使用其参数映射功能进行验证(此方法支持)。您能否详细说明为什么我不应该为此使用 Dapper?我有点困惑。
    • ORM 通常用于将数据填充到具有固定属性名称的 POCO 类中,从在运行时 before 预先确定的 SQL 语句中。通过尝试使用 Dapper 从 运行时生成的 SQL 语句进行填充,您首先颠覆了拥有 ORM 的全部意义。
    • 好的;我认为这里的部分困惑是,当我说“用户编写 SQL”时,我的真正意思是“其他开发人员编写 SQL”,这意味着查询是在运行时之前写入使用我的库/方法的代码中。跨度>
    猜你喜欢
    • 2013-11-20
    • 1970-01-01
    • 1970-01-01
    • 2020-06-14
    • 1970-01-01
    • 2022-10-08
    • 1970-01-01
    • 2013-05-04
    • 2015-01-23
    相关资源
    最近更新 更多