【问题标题】:DataReader Exception数据读取器异常
【发布时间】:2016-05-27 20:05:57
【问题描述】:

我有一个正在使用的简单数据库。它包含两个用户条目,一个用户 ID 为 1,IsAdmin 为 0,另一个用户 ID 为 3041234567,IsAdmin 为 1。数据库中的唯一字段是字符串 UserID 和一个位 IsAdmin。我正在使用以下代码从数据库中读取:

SqlConnection conn = new SqlConnection(Properties.Settings.Default.Conn);
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM Users WHERE UserID = " + t.Text.ToString(), conn);
SqlDataReader reader = cmd.ExecuteReader();

if (reader.HasRows)
{

    while (reader.Read())
         {
                user.UserID = reader["UserID"].ToString();
                user.IsAdmin = Convert.ToBoolean(reader["IsAdmin"]);
         }
}

conn.Close();

如果我输入数字 3041234567 作为用户 ID,一切正常,但如果我输入数字 1,我会得到一个异常,说“nvarchar 值 '3041234567' 的转换溢出了一个 int 列。”

如果我设置断点并观察 while(reader.read()) 循环,循环将很好地迭代并设置 user.UserID = 1 和 user.IsAdmin = false。当循环开始第二次迭代时抛出异常。我想我有几个问题:

  1. 为什么循环要第二次迭代?
  2. 如何使用sql命令"SELECT * FROM Users WHERE UserID = 1"返回ID 3041234567
  3. 正在溢出的 int 列是什么?

【问题讨论】:

  • 如果您只使用 WHERE 语句检索 1 条记录,请删除循环。另外为什么你的 UserID 是一个字符串?数据库中列的数据类型是什么?请注意,带符号的 int 最大为 2147483647。您的第二个条目的 UserID 超出了可接受的 int 值。
  • 就个人而言,在获取数据时,我总是使用数据表来将结果返回,因为获取和放置数据要容易得多。但是...在您的实例中,如果循环不止一次,您将返回多少行。此外,当您输入该值并设置断点时,t.text 的值是多少?然后整个 Select Statment 的值是多少
  • 第一个问题:您的代码容易受到 SQL 注入攻击。我会强烈建议您使用参数化 SQL。
  • Jon 有一个很好的观点,这就是我将在我的下一个 cmets 中谈到的内容
  • 我明白了。我会改变的。

标签: c# sql loops sqldatareader sqlcommand


【解决方案1】:

好吧,因为

  3041234567 > int.MaxValue ( == 2147483647)

你有一个溢出;但是,如果您想要某种整数值,请尝试long(64 位长):

  long value = Convert.ToInt64(reader["UserID"]);

类似这样的:

 // Wrap IDisposable into using 
 using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.Conn)) {
   conn.Open();

   // Make sql 
   //  1. Readable 
   //  2. Parametrized
   //  3. Avoid * in select
   String sql = 
     @"select UserID,
              IsAdmin
         from Users
        where UserID = @prm_UserId";

   // Wrap IDisposable into using 
   using (SqlCommand cmd = new SqlCommand(sql, conn)) {
     // Explicit data type will be better here (Add Parameter with type)
     // but I don't know it
     cmd.Parameters.AddWidthValue("prm_UserId", t.Text);  

     // Wrap IDisposable into using 
     using (SqlDataReader reader = cmd.ExecuteReader()) {
       // You don't want to iterate the whole cursor, but the first record 
       if (reader.Read()) {
         //TODO: Make UserID being "long"
         user.UserID = Convert.ToInt64(reader["UserID"]);
         user.IsAdmin = Convert.ToBoolean(reader["IsAdmin"]);
       } 
     }
   }
 } 

【讨论】:

  • 如果我将任何数据存储为 Int,这将起作用,但我不是。我的应用程序和数据库中的用户 ID 是一个字符串。因此,关于什么 int 列被溢出的问题。但是,通过将 while(reader.read()) 循环更改为 if 语句确实解决了我的问题。
  • 如果UserId在数据库中声明为Char(N)VarChar(N)等,但实际上只有数字你可以将其转换为长Convert.ToInt64();您还必须更改 User 类 - 字段/方法 UserID 必须是 long
  • 我不想要它们那么久。我需要它是一个字符串。不确定我们将使用哪种 UserID 格式。他们可能决定在 UserID 中包含来自用户名字和姓氏的字母。
  • 如果您希望项目为String,只需转换为Stringuser.UserID = Convert.ToString(reader["UserID"]);
  • @ProgrammingDude:不要获取您不需要的数据:您只需要两个字段(不是全部其中),因此查询这两个字段。 * 可能很昂贵(如果您在表中有 照片 用户怎么办),容易出错(如果您获取复杂类型字段怎么办)
猜你喜欢
  • 2021-07-08
  • 1970-01-01
  • 1970-01-01
  • 2018-12-06
  • 1970-01-01
  • 1970-01-01
  • 2014-10-28
  • 2018-10-26
  • 2021-12-12
相关资源
最近更新 更多