带有SqlParameters的SqlDataReader

问题描述 投票:2回答:3

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

我之前使用它并且它有效,但在这种情况下似乎有一个问题,我无法理解。

我正在使用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()永远不会返回任何价值。

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

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

EventSink ='cmd.EventSink'抛出类型'System.InvalidCastException'的异常

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

Screeenshot from debug on cmd

我一直在寻找各地,但我对如何继续前进毫无头绪。

有什么想法吗?

UPDATE

我最终成功完成了这项工作。

我已经放弃了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);
        }

    }

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

c# sql sql-server-2012
3个回答
0
投票

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


0
投票

没有编译或运行时错误与空DataReader告诉我这是你的WHERE条款的问题。以下是您可能会提到的一些地方:

  1. 没有通配符的LIKE%)与SQL中的=相同。 LIKE相当于“equals | starts-with | ends-with | contains”,具体取决于放置通配符[s]的位置。要搜索整个字段(“包含”),您可以执行以下操作: parameters[8].Value = string.Format("%{0}%", dr["Activity"].ToString());
  2. 你的WHERE子句的结构方式,你必须在所有字段上都有一个完美的匹配,并且没有参数可以为null或为空。对于未使用所有参数的情况,您将需要处理空/空输入值。不确定这是否是一个用例,但它是一个常见的问题。使用这样的分组逻辑: 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)。我通常更喜欢第一种方法,因为它是明确的空格,但这取决于你。


0
投票

您需要记住处理,为方便起见,我还鼓励优先选择多行字符串文字而不是普通字符串。这样可以更轻松地编辑/复制/粘贴/等等。

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.
© www.soinside.com 2019 - 2024. All rights reserved.