Как вставить несколько строк в MySql, используя C #, где столбцы имеют даты? - PullRequest
0 голосов
/ 07 ноября 2018

Следующий класс захватывает SendQueue объекты из API json ответы:

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

}

Когда я получаю объект, я конвертирую значение SendDate в строку для вставки в базу данных MySQL, но форматирование, по-видимому, не принимается БД, поэтому вставка завершается неудачно.

Когда я преобразую значение в строку, форматирование SendDate будет "дд / мм / гггг чч: мм: сс" , тогда как база данных принимает "гггг-ММ-дд чч: мм: сс ".

Конечно, лучший способ справиться с этим - через параметризованные запросы. Но так как я использую пакетные вставки, я не могу использовать объекты DateTime.

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

У меня будет такая же проблема, если я также использую Bulk Insert , поскольку даты в конечном итоге будут преобразованы в строки, хранящиеся в файле.

Ответы [ 2 ]

0 голосов
/ 07 ноября 2018

По вашему обновленному вопросу, похоже, корень проблемы в том, что вам нужен способ вставки нескольких строк с помощью одного оператора вставки.

В идеале вы должны предоставить хранимую процедуру, которая может принимать тип таблицы в качестве входных данных, как это может быть сделано в мире SqlServer: Вставить весь DataTable в базу данных сразу вместо строки за строкой?

Учитывая, что это не вариант для 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
    }
}
0 голосов
/ 07 ноября 2018

Вы должны использовать соответствующий DateTime тип в вашей схеме. Не используйте строки для представления Date s или DateTime s или Time s, чисел или чего-либо еще, кроме собственной строки.

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
}

Пакетная вставка

Вам не нужно запускать один оператор вставки за раз. Вы можете легко создать одну инструкцию с несколькими кортежами, которые вы хотите вставить. Вот пример кода C #, который делает это с 1 столбцом. Вы можете легко расширить это с несколькими значениями для кортежа.

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, см. Этот предыдущий ответ: Когда использовать VARCHAR и DATE / DATETIME . Я процитирую важные вещи:

Некоторые недостатки версии VARCHAR:

  • Вы не можете легко добавлять / вычитать дни к версии VARCHAR.
  • Труднее извлечь только месяц / год.
  • Ничто не мешает помещать устаревшие данные в столбец VARCHAR в базе данных.
  • Версия VARCHAR зависит от культуры.
  • Вы не можете легко отсортировать даты.
  • Трудно изменить формат, если вы хотите позже.
  • Это нетрадиционно, что усложнит понимание другим разработчикам.
  • Во многих средах использование VARCHAR будет занимать больше места для хранения. Это может не иметь значения для небольших объемов данных, но в коммерческих средах с миллионами строк данных это вполне может иметь большое значение.

Часовые пояса и значения

Не забывайте о часовых поясах, если это применимо к вашему приложению. Рекомендуется всегда хранить значение DateTime UTC в базе данных вместо значения местного часового пояса. Затем значение UTC может быть отправлено на уровень представления, где уровень представления отвечает за применение к значению местного часового пояса (необязательно). Некоторые инфраструктуры пользовательского интерфейса имеют встроенные механизмы для этого в элементах управления DateTime. Опять же, обратное также верно, пусть уровень представления преобразует любой ввод в значение UTC DateTime и отправляет его обратно в стек вызовов на сервер.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...