【问题标题】:Why does this ADO.NET query return no results?为什么此 ADO.NET 查询不返回任何结果?
【发布时间】:2019-10-27 20:46:29
【问题描述】:

我有以下代码执行 SQL 语句并查找结果。

var sql = @"select BOQ_IMPORT_ID "
          + "from ITIS_PRJ.PRJ_BOQ_IMPORT_HEADER "
          + "where PROJECT_ID = :Projectid "
          + "order by CREATED_ON desc "
          + "fetch first 1 row only";
using (var conn = new OracleConnection(ApplicationSettings.ConnectionString))
using (var cmd = new OracleCommand(sql, conn))
{
    conn.Open();
    cmd.Parameters.Add(LocalCreateParameterRaw("ProjectId", projectId));
    var reader = cmd.ExecuteReader();
    if (reader.Read())
    {
        byte[] buffer = new byte[16];
        reader.GetBytes(0, 0, buffer, 0, 16);
        var boqId = new Guid(buffer);
        return boqId;
    }

    return null;
}

LocalCreateParameterRaw 声明为:

public static OracleParameter LocalCreateParameterRaw(string name, object value)
{
    OracleParameter oracleParameter = new OracleParameter();
    oracleParameter.ParameterName = name;
    oracleParameter.OracleDbType = OracleDbType.Raw;
    oracleParameter.Size = 16;
    oracleParameter.Value = value;
    return oracleParameter;
}

“projectId”的基础类型是“Guid”。

if (reader.Read()) 的计算结果始终为 false,尽管表中只有一行。它通常应该只返回一行。

使用GI Oracle Profiler,我可以捕获发送到数据库的SQL,但只有一次分析器为:ProjectId 参数提供了一个值,而且它是小写的。就像它没有返回任何结果一样,但是一旦我将UPPER 应用于该值,我就会得到一个结果。

看起来我必须以某种方式将参数转换为大写才能使查询工作,但我不知道如何。但是,如果我在 projectId GUID 上执行 ToString().ToUpper(),则会收到参数绑定错误。

非常重要: 我已经尝试完全删除where 子句,不再添加参数,所以应该返回表中的所有行,但仍然没有结果。

【问题讨论】:

  • 如果您的查询总是只返回一行一列,那么您可以考虑cmd.ExecuteScalar();
  • @WernfriedDomscheit 不。 ExecuteScalar 返回null。
  • @ProfK - 看看这是否直接相关,它与 Guid 在 .net 和 oracle 之间的翻译方式有关。 Convert from Oracle's RAW(16) to .NET's GUID
  • 如果您仍然遇到问题,如果您包含基础类型和变量 projectId 的值(变量用作查询中的参数),将会有所帮助。
  • @Igor 我已经添加了,类型是'Guid'。

标签: oracle ado.net oracle12c datareader


【解决方案1】:

使用更通用的方法,尝试以下方法

var sql = "SELECT BOQ_IMPORT_ID "
      + "FROM ITIS_PRJ.PRJ_BOQ_IMPORT_HEADER "
      + "WHERE PROJECT_ID = :projectid "
      + "ORDER BY CREATED_ON DESC "
      + "FETCH FIRST ROW ONLY";
using (DbConnection conn = new OracleConnection(ApplicationSettings.ConnectionString))
using (DbCommand cmd = conn.CreateCommand()) {
    DbParameter parameter = cmd.CreateParameter();
    parameter.ParameterName = "projectid";
    parameter.Value = projectId.ToString("N").ToUpper(); //<-- NOTE FORMAT USED

    cmd.Parameters.Add(parameter);
    cmd.CommandType = CommandType.Text;
    cmd.CommandText = sql;

    conn.Open();

    var reader = cmd.ExecuteReader();
    if (reader.Read()) {
        var boqId = new Guid((byte[])reader[0]);
        return boqId;
    }
    return null;
}

看起来我必须以某种方式将参数转换为大写才能使查询工作,但我不知道如何。但是,如果我在 projectId GUID 上执行 ToString().ToUpper(),则会收到参数绑定错误。

参考Guid.ToString Method

说明符 N 将其格式化为 32 位数字:00000000000000000000000000000000

如果未提供格式,则默认格式为 D,其中包括用连字符分隔的 32 位数字。

00000000-0000-0000-0000-000000000000

这可以解释您的绑定错误。

【讨论】:

    【解决方案2】:

    我不知道如何,但是将 SQL 字符串设为逐字字符串(以 @ 为前缀)会导致 proc 工作。因此,它不适用于:

    var sql = @"SELECT BOQ_IMPORT_ID "
          + "FROM ITIS_PRJ.PRJ_BOQ_IMPORT_HEADER "
          + "WHERE PROJECT_ID = :projectid "
          + "ORDER BY CREATED_ON DESC "
          + "FETCH FIRST ROW ONLY";
    

    但在 SQL Developer 中执行相同的命令字符串并返回结果。当我逐字制作 SQL 字符串时,如下所示,我得到了结果。

    var sql = @"select BOQ_IMPORT_ID 
                from ITIS_PRJ.PRJ_BOQ_IMPORT_HEADER 
                where PROJECT_ID = :ProjectId 
                order by CREATED_ON desc 
                fetch first 1 row only";
    

    【讨论】:

    • 哇。好的。如果从第一个示例中删除 @ 会发生什么。
    • 我完全错过了第一个字符串的前缀。
    • @Nkosi 哇,如果我从第一个示例中删除 @,它也可以工作。
    • @ProfK 源代码是否有可能包含不可见的字符(不可破坏的空格,空符号,...)?您可以执行一个测试:var sql = @"SELECT BOQ_IMPORT_ID FROM ITIS_PRJ.PRJ_BOQ_IMPORT_HEADER" + "WHERE PROJECT_ID = :projectid " 如果它返回所有行,则表示逐字以空字符结尾(空字符 '\0' 用于终止 C 字符串)
    • @LukaszSzozda 我怀疑是这种情况,因为逐字逐句和串联字符串之间的更改会改变结果。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多