如何使用C#在列中有日期的行中将多行插入MySql?

时间:2018-11-07 10:45:37

标签: c# datetime

以下类从API json响应中捕获 SendQueue 对象:

public class SendQueue
{
    public DateTime SendDate { get; set; }
    public int StatusCode { get; set; }
    public string StatusMessage { get; set; }

}

当我收到对象时,我将SendDate值转换为字符串以插入到MySQL数据库中,但是显然数据库不接受该格式,因此插入失败。

当我将值转换为字符串时,SendDate的格式为“ dd / MM / yyyy hh:mm:ss” ,而数据库接受“ yyyy-MM-dd hh :mm:ss“

当然,处理此问题的更好方法是通过参数化查询。但是由于使用批处理插入,所以无法使用DateTime对象。

INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);

如果我也use Bulk Insert,我也会遇到同样的问题,因为日期最终将转换为文件中存储的字符串。

2 个答案:

答案 0 :(得分:2)

您应该在架构中使用适当的DateTime type。请勿使用字符串来表示DateDateTimeTime,数字或任何其他非本地字符串的字符串。

MySql允许以下架构类型:

DATE
TIME
DATETIME
TIMESTAMP
YEAR

在这种情况下,最合适的是DATETIME。这与.net类型System.DateTime保持一致。如果使用的是ADO.NET,则应在查询中使用参数。示例:

using(MySqlCommand m = new MySqlCommand("INSERT INTO table (sendDate) VALUES (@sendDate)"))
{
     m.Parameters.Add("@sendDate", MySqlDbType.DateTime).Value = myObj.SendDate;
     // rest of code
}

批量插入

您不必一次运行一个插入语句。您可以轻松地创建一个包含多个要插入的元组的语句。这是使用1列执行此操作的示例c#代码。您可以使用每个元组的多个值轻松扩展它。

var sql = "INSERT INTO table (sendDate) VALUES (";
var parameters = input.Select((queue, i) => new MySqlParameter("@sendDate" + i.ToString(), MySqlDbType.DateTime)).ToArray();
sql += string.Join("), (", parameters.Select(_ => _.ParameterName)) + ")";
for (int i = 0; i < parameters.Length; i++)
{
    parameters[i].Value = input[i].SendDate;
}

using(var connection = new MySqlConnection(connectionString))
using(var command = new MySqlCommand(sql, connection))
{
  command.Parameters.AddRange(parameters);
  connection.Open();
  command.ExecuteScalar();
}

何时进行转换?

代码堆栈应始终在调用堆栈中尽可能晚地将DateTime转换为string,通常是在表示层中(此时人类必须阅读)。反之亦然,应该将string输入转换为DateTime,以便尽可能早地遍及调用堆栈(同样,在表示层)。


为什么不使用varchar作为日期?

如果您想知道为什么 ,则不应将DateTime存储为string,请参见前面的答案:When to use VARCHAR and DATE/DATETIME。我会引用重要的内容:

  

VARCHAR版本的一些缺点:

     
      
  • 您无法轻松地为VARCHAR版本添加/减去天数。
  •   
  • 每月/每年都很难提取。
  •   
  • 没有什么可以阻止您将非日期数据放入数据库的VARCHAR列中。
  •   
  • VARCHAR版本是特定于文化的。
  •   
  • 您无法轻松地对日期进行排序。
  •   
  • 如果以后要更改格式,将很困难。
  •   
  • 这是非常规的,这会使其他开发人员更难以理解。
  •   
  • 在许多环境中,使用VARCHAR将使用更多的存储空间。对于少量数据而言,这可能无关紧要,但是在具有数百万行数据的商业环境中,这可能会带来很大的不同。
  •   

时区和值

如果这适用于您的应用程序,请不要忘记时区。建议始终在数据库中存储DateTime UTC值而不是本地时区值。然后,可以将UTC值发送到表示层,其中表示层负责将本地时区应用于该值(可选)。一些UI框架在DateTime控件中内置了用于执行此操作的机制。同样,反之亦然,让表示层将任何输入转换为UTC DateTime值,然后将其向下返回到调用堆栈中。

答案 1 :(得分:0)

对于每个更新的问题,看来根本的问题是您需要一种通过单个插入语句插入多行的方法。

理想情况下,您将提供一个存储过程,该存储过程可以接受表类型作为输入,就像在SqlServer世界中一样:Insert entire DataTable into database at once instead of row by row?

鉴于在撰写本文时这不是MySQL的选择,但是有一些替代方案...

如果由于需要在同一事务中插入所有行而需要执行此操作,只需将插入内容包装在事务中即可。代码将是这样的(未经我的试用,因为我没有MySQL)。

public void InsertMySql(string connectionString, string command, DataTable data)
{
    using (var connection = new MySqlConnection(connectionString))
    {
        connection.Open();

        using (var transaction = connection.BeginTransaction())
        {
            try
            {
                using (MySqlCommand cmd = new MySqlCommand(command, connection))
                {
                    cmd.CommandType = CommandType.Text;
                    foreach (var row in data.Rows)
                    {
                        cmd.Parameters.Clear();
                        foreach (var cell in data.Columns)
                        {
                            cmd.Parameters.AddWithValue($"@{cell.Name}", row[cell]);
                        }
                        cmd.ExecuteNonQuery();
                    }
                }
                transaction.Commit();
            }
            catch 
            {
                transaction.Rollback();
                throw;
            }
        }
    }
}

如果出于性能原因需要执行此操作,则另一种选择可能是查看第三方库,例如:https://github.com/zzzprojects/Bulk-Operations。我没有亲自尝试过,但是该库看起来很有希望/发布者(zzzprojects)非常知名并受人尊敬/维护了流行的SQL Fiddle网站以及其他项目。

public static void InsertMySql(string connectionString, DataTable data)
{
    using (var connection = new MySqlConnection(connectionString))
    {
        connection.Open();
        var bulk = new BulkOperation(connection);
        bulk.BulkInsert(data); //assumes your data table's table name, column names/definitions match your table's; I think.  See https://bulk-operations.net/bulk-insert for what documentation's available
    }
}