【问题标题】:SqlDataReader with SqlParameters带有 SqlParameters 的 SqlDataReader
【发布时间】:2017-05-31 12:37:47
【问题描述】:

我正在尝试运行依赖于参数的查询。

我以前用过它,它可以工作,但在这种情况下,似乎有一个问题,我无法理解。

我使用的是 SQL Server 2012。

这是我的代码:

 public void getMissingKeys()
 {
        SqlConnection conn = new SqlConnection(_connection);

        conn.Open();

        foreach(DataRow dr in _result.Rows)
        {
            string sqlSearch = "SELECT TOP 1 [Column1], 
             [Column2], [Column3], [Column4], [Column5], 
             [Column6], [Column7], [Column8] 
             FROM KeyValuationActual_destination 
             WHERE [SystemType] = @system 
             AND [DataType] = @data 
             AND [Location] LIKE @location 
             AND [Department] LIKE @department 
             AND [Role] LIKE @role 
             AND [Language] LIKE @language 
             AND [Shift] LIKE @shift
             AND [ResourceID] = @resource
             AND [Activity] LIKE @activity AND
             [Unique ID] IS NOT NULL";
            SqlCommand cmd = new SqlCommand(sqlSearch, conn);

            SqlParameter[] parameters = new SqlParameter[9];
            parameters[0] = new SqlParameter("@system", SqlDbType.Float);
            parameters[0].Value = dr["SystemType"];

            parameters[1] = new SqlParameter("@data", SqlDbType.Float);
            parameters[1].Value = dr["DataType"];

            parameters[2] = new SqlParameter("@location", SqlDbType.VarChar, 255);
            parameters[2].Value = dr["Location"].ToString();

            parameters[3] = new SqlParameter("@department", SqlDbType.VarChar, 255);
            parameters[3].Value = dr["Department"].ToString();

            parameters[4] = new SqlParameter("@role", SqlDbType.VarChar, 255);
            parameters[4].Value = dr["Role"].ToString();

            parameters[5] = new SqlParameter("@language", SqlDbType.VarChar, 255);
            parameters[5].Value = dr["Language"].ToString();

            parameters[6] = new SqlParameter("@shift", SqlDbType.VarChar, 255);
            parameters[6].Value = dr["Shift"].ToString();

            parameters[7] = new SqlParameter("@resource", SqlDbType.Float);
            parameters[7].Value = dr["ResourceID"];

            parameters[8] = new SqlParameter("@activity", SqlDbType.VarChar, 255);
            parameters[8].Value = dr["Activity"].ToString();

            foreach (SqlParameter param in parameters)
            {
                cmd.Parameters.Add(param);
            }


            SqlDataReader reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                //Do something
            }
        }

        conn.Close();
}

Column1..8 是虚构名称。

不知何故,我看到参数实际上被正确查询并返回,但SqlDataReader 似乎无法处理变量以在查询命令中“替换”它们。

所以reader.Read() 永远不会返回任何值。

我想知道它是否是参数类型(我也尝试对 VarChars 使用 nullables)。

在调试时,如果我检查 cmd 并前往“非公共成员”,我会看到两个错误:

EventSink = 'cmd.EventSink' 引发了“System.InvalidCastException”类型的异常

InternalSmiConnection = 'cmd.InternalSmiConnection' 引发了“System.InvalidCastException”类型的异常

Screeenshot from debug on cmd

我一直在到处寻找,但我不知道如何继续。

有什么想法吗?

更新

我最终设法完成了这项工作。

我已经放弃了 ExecuteReader,因为它不能检索行,甚至与 DataTable 结合使用。似乎如果你想使用参数它的字符串类型,并且由于表使用 Float 作为类型,这让我很头疼尝试匹配类型。

我结束了使用 SqlAdapater、DataTable 和参数。似乎参数的类型不是那么强,因为我不需要进行任何强制转换。

这就是我最终得到的代码:

public void getMissingKeys()
    {
        SqlConnection conn = new SqlConnection(_connection);
        string sqlSearch = "SELECT TOP 1 "+
                    "[Column1], [Column2], [Column3], "+
                    "[Column4], [Column5], [Column6], "+
                    "[Column7], [Column8] "+
                    "FROM KeyValuationActual_destination "+
                    "WHERE [SystemType] = @system "+
                    "AND [DataType] = @data "+
                    "AND [Location] LIKE @location "+
                    "AND [Department] LIKE @department "+
                    "AND [Role] LIKE @role "+
                    "AND [Language] LIKE @language "+
                    "AND [Shift] LIKE @shift "+
                    "AND [Resource Utilisation Ref_ID] = @resource "+
                    "AND [Activity] LIKE @activity "+
                    "AND [Unique ID] IS NOT NULL";

        try {
            foreach (DataRow dr in _result.Rows)
            {
                conn.Open();

                SqlDataAdapter da = new SqlDataAdapter(sqlSearch, conn);
                da.SelectCommand.Parameters.AddWithValue("@location", dr[2]);
                da.SelectCommand.Parameters.AddWithValue("@department", dr[3]);
                da.SelectCommand.Parameters.AddWithValue("@role", dr[4]);
                da.SelectCommand.Parameters.AddWithValue("@language", dr[5]);
                da.SelectCommand.Parameters.AddWithValue("@shift", dr[7]);
                da.SelectCommand.Parameters.AddWithValue("@resource", dr[8]);
                da.SelectCommand.Parameters.AddWithValue("@activity", dr[9]);
                da.SelectCommand.Parameters.AddWithValue("@data", dr[10]);
                da.SelectCommand.Parameters.AddWithValue("@system", dr[11]);

                DataTable dataTable = new DataTable();
                da.Fill(dataTable);

                if(dataTable != null)
                {
                    foreach(DataRow keyRow in dataTable.Rows)
                    {
                        dr[13] = keyRow["Column1"];
                        dr[14] = keyRow["Column2"];
                        dr[15] = keyRow["Column3"];
                        dr[16] = keyRow["Column4"];
                        dr[17] = keyRow["Column5"];
                        dr[18] = keyRow["Column6"];
                        dr[19] = keyRow["Column7"];
                        dr[20] = keyRow["Column8"];
                    }

                }
            conn.Close();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Querying keys exception information! : {0}", ex);
        }
        
    }

如果您认为可以在此代码中改进某些内容,我愿意接受建议

【问题讨论】:

  • 我注意到一些likes 表达式,如果你在参数值或查询中不添加'%',它不会被视为喜欢,你认为这可能是问题所在?
  • 删除所有参数并运行查询。希望你会得到许多行中的第一行。一次添加一个参数,直到它“中断”
  • 那些异常无关紧要,这只是调试器尽最大努力访问它可能访问的所有数据。您几乎总是会看到一些这样的例外情况,但这并不意味着它们一定是问题。我同意 kblok,如果您不使用通配符,LIKEs 将被视为=
  • AFAIK,EventSinkInternalSmiConnection 都是非公共成员,它们不常用于常规连接。在迭代内容之前使用HasRows 检查SqlDataReader 是否有结果。
  • @TetsuyaYamamoto,仅转发是一个问题吗?我从未听说过 SqlDataReader 的问题。

标签: c# sql sql-server-2012


【解决方案1】:

您的 SqlDbType 枚举都正确吗? “系统类型”、“数据类型”和“资源ID”实际上是浮动的吗?

【讨论】:

  • 是的。我将这些基于实际的数据库设计。
【解决方案2】:

空的DataReader 没有编译或运行时错误告诉我这是您的WHERE 子句的问题。这里有一些你可能会刺激的地方:

  1. 不带通配符的LIKE (%) 与 SQL 中的 = 相同。 LIKE 等同于“equals|starts-with|ends-with|contains”,具体取决于您将通配符 [s] 放在哪里。要搜索整个字段(“包含”),您可以执行以下操作:
    parameters[8].Value = string.Format("%{0}%", dr["Activity"].ToString());

  2. 您的WHERE 子句的结构方式,您必须在所有字段上完美匹配,并且任何参数都不能为空或空。对于未使用所有参数的情况,您将需要处理空白/空输入值。不确定这是否是一个用例,但这是一个常见的问题。使用这样的分组逻辑:

    AND ([Department] LIKE @department 
       OR @department IS NULL 
       OR @department  = '')
    AND (AND [Role] LIKE @role 
       OR @role IS NULL 
       OR @role = '')
    
  3. 为什么不对UniqueID 字段进行过滤?你只是检查它是否为空。这似乎是一个主键。在可能的情况下,过滤主键是一种很好的做法。

  4. 正如@n8wrl 所建议的那样,尝试运行不带WHERE 子句和不带参数的查询。你应该得到一个结果,如果没有,你的问题不是 SQL。重新添加字段并进行测试,直到您停止获得结果。许多问题的解决归结为将问题分解成小块。

在半相关的注释中,我有一个代码样式和 SO-meta 建议:线宽限制。在您编写代码的任何地方设置一个软限制,例如 50-100 个字符。我在编辑之前就在这里,您在一行上的长字符串文字在尝试分析您的问题时创造了额外的工作。当您在一两年内重新访问此代码时,您更愿意看到哪一个?

//Better one...
string sqlSearch = "SELECT TOP 1 [Column1], [Column2], [Column3], [Column4], [Column5], [Column6], [Column7], [Column8] FROM KeyValuationActual_destination WHERE [SystemType] = @system AND [DataType] = @data AND [Location] LIKE @location AND [Department] LIKE @department AND [Role] LIKE @role AND [Language] LIKE @language AND [Shift] LIKE @shift AND [ResourceID] = @resource AND [Activity] LIKE @activity AND [Unique ID] IS NOT NULL";

//...or two?
string sqlSearch = 
  "SELECT TOP 1 " + 
     "[Column1], [Column2], [Column3], " + 
     "[Column4], [Column5], [Column6], " + 
     "[Column7], [Column8] " + 
  "FROM KeyValuationActual_destination " + 
  "WHERE [SystemType] = @system " + 
     "AND [DataType] = @data " + 
     "AND [Location] LIKE @location " + 
     "AND [Department] LIKE @department " + 
     "AND [Role] LIKE @role " + 
     "AND [Language] LIKE @language " + 
     "AND [Shift] LIKE @shift " + 
     "AND [ResourceID] = @resource " + 
     "AND [Activity] LIKE @activity " + 
     "AND [Unique ID] IS NOT NULL";

“更漂亮”的替代方法是C# verbatim string(参见示例中的字符串 j)。我通常更喜欢第一种方法,因为它对空格很明确,但这取决于你。

【讨论】:

  • 嘿...很好的建议 CaptainMarvel。我真的看到你要去哪里。不要试图责怪其他人,但这就是该表的结构方式,我试图根据以前的条目“猜测”一些值,为此我需要在一行中匹配一些值以便查找它在前几行。这没问题,因为我只是在测试这个,我知道我应该得到哪些匹配。我没有返回这些匹配项,以便我可以查看它们。我想这可以解决第 1,2 和 3 点
  • 我也试过直接在服务器中运行查询,它可以工作,但似乎涉及SqlReader不适用于此代码
【解决方案3】:

您需要记住 dispose,为了方便起见,我还鼓励您优先使用多行字符串文字而不是普通字符串。这将使编辑/复制/粘贴/等变得更加容易。

var dataTable = new DataTable();
var sql = @"
  SELECT TOP 1
  FROM KeyValuationActual_destination
  WHERE [SystemType] = @system
  ";
using (var conn = new SqlConnection(_connection))
{
  conn.Open();
  using (var da = new SqlDataAdapter(sql, conn))
  {
    // blah blah blah
    da.Fill(dataTable);
  }
}
// "using" statements avoid the need to manually Close(), Dispose(), etc.

【讨论】:

    猜你喜欢
    • 2017-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多