【问题标题】:String meant to store date in a table is converting an int for unknown reason用于在表中存储日期的字符串由于未知原因正在转换 int
【发布时间】:2020-05-02 08:20:15
【问题描述】:

我正在尝试将日期作为字符串存储在表格中,但日期不断转换为与日期相关的负 4 位数字,我终生无法弄清楚在哪里我搞砸了。请注意,我使用的是 C# 和 SQL Server 的组合

foreach(DataRow dr in dt.Rows)
{
    int qty = 0;
    string pname = "";

    SqlCommand cmd3 = con.CreateCommand();
    cmd3.CommandType = CommandType.Text;
    cmd3.CommandText = "insert into order_item values('" + orderid.ToString() + "','" + dr["product"].ToString() + "'," +
        "'" + dr["price"].ToString() + "','" + dr["qty"].ToString() + "','"+ dr["total"].ToString() + "')";
    cmd3.ExecuteNonQuery();

    qty = Convert.ToInt32(dr["qty"].ToString());
    pname = dr["product"].ToString();

    SqlCommand cmd6 = con.CreateCommand();
    cmd6.CommandType = CommandType.Text;
    cmd6.CommandText = "update stock set product_qty = product_qty - " + qty + " where product_name = '"+pname.ToString()+"'";
    cmd6.ExecuteNonQuery();

    // date keeps getting updated to negative 4 digit number which coordinates with the date. ex: 14-01-2020 is converting to -2007.
    SqlCommand cmd7 = con.CreateCommand();
    cmd7.CommandType = CommandType.Text;
    **cmd7.CommandText = "update stock_over_time set product_qty = product_qty - " + qty + ", date_changed = " + date.ToString("dd-MM-yyyy") + "" +
        " where product_name = '" + pname.ToString() + "'";**
    cmd7.ExecuteNonQuery();
}

【问题讨论】:

  • 原因已知 - 字符串连接。它将代码暴露给 SQL 注入和转换错误。改用适当的参数化查询
  • 将值连接成字符串以生成 SQL 是第一个主要问题;有没有好处可以来自 - (搜索:“SQL注入”)
  • 更好的是,谷歌搜索Bobby Tables。想象一下如果product 字段包含值'; drop table Users;-- 会发生什么
  • 另一个严重的转换错误,使用dd-MM-yyyy 作为日期文字。这是一个 localized 字符串,例如在美国无法识别,或者导致错误的日期,例如 4 月 7 日而不是 7 月 4 日。如果您使用日期,则不会有任何此类问题-类型参数
  • SQL Server 有不止一种 DataTime 类型。检查服务器中的类型。可能是日期存储不正确,因此当您使用 SQL Server Management Studio 时,请查询数据库以验证日期是否正确。

标签: c# sql sql-server string date


【解决方案1】:

直接的问题是:

    , date_changed = " + date.ToString("dd-MM-yyyy") + "

会变成

    , date_changed = 15-01-2020

这是:-2006,这是(因为日期的存储方式)1894 年 7 月的某个时间。

bad 解决此问题的方法是添加引号,但这是:bad - 它有一系列与国际化有关的问题(是 08-01 8 月 1 日?1 月 8 日?)、SQL 注入等

正确的解决方法是始终使用参数。例如:

cmd7.CommandText = @"
    update stock_over_time
    set    product_qty = product_qty - @qty,
           date_changed = @date
    where  product_name = @pname";

但是,这需要您添加带有值的参数。

最简单的方法是使用 Dapper:

string pname = ...
int qty = ...
DateTime date = ...
con.Execute(@"
    update stock_over_time
    set    product_qty = product_qty - @qty,
           date_changed = @date
    where  product_name = @pname",
    new { pname, qty, date });

注意:所有您的数据库访问都应该参数化,或者像上面那样,或者使用原始 ADO.NET,或者使用像 EF 等工具。不仅仅是这个地方; 无处不在

【讨论】:

    【解决方案2】:

    不应将日期存储为字符串数据类型,而应将date-changed 更改为日期时间类型(甚至只是日期,因为存储的值没有“时间”元素)。

    另外,建议使用参数化查询来避免 SQL 注入

    string sql = @"update stock_over_time set product_qty = product_qty - @qty, date_changed = @date where product_name = @pname";
    
    using (SqlConnection connection = new SqlConnection(connString)
    {
      connection.Open();
      using (SqlCommand cmd= new SqlCommand(sql, connection))
      {
         cmd.Parameters.Add("@qty", SqlDbType.SqlInt32).value = qty;  
         cmd.Parameters.Add("@date", SqlDbType.SqlDateTime).value =  date;
         cmd.Parameters.Add("@pname", SqlDbType.Varchar, 50).value = pname;
         cmd.ExecuteNonQuery();
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-19
      • 1970-01-01
      • 1970-01-01
      • 2016-01-13
      • 1970-01-01
      • 1970-01-01
      • 2014-11-23
      • 1970-01-01
      相关资源
      最近更新 更多