У меня есть запрос на вставку строки в таблицу, в которой есть поле с именем ID, которое заполняется с помощью AUTO_INCREMENT в столбце. Мне нужно получить это значение для следующего бита функциональности, но когда я запускаю следующее, оно всегда возвращает 0, даже если фактическое значение не равно 0:
MySqlCommand comm = connect.CreateCommand();
comm.CommandText = insertInvoice;
comm.CommandText += "\'" + invoiceDate.ToString("yyyy:MM:dd hh:mm:ss") + "\', " + bookFee + ", " + adminFee + ", " + totalFee + ", " + customerID + ")";
int id = Convert.ToInt32(comm.ExecuteScalar());
Насколько я понимаю, это должно вернуть столбец идентификатора, но каждый раз он просто возвращает 0. Любые идеи?
Обновлено:
Когда я бегу:
"INSERT INTO INVOICE (INVOICE_DATE, BOOK_FEE, ADMIN_FEE, TOTAL_FEE, CUSTOMER_ID) VALUES ('2009:01:01 10:21:12', 50, 7, 57, 2134);last_insert_id();"
Я получил:
{"You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'last_insert_id()' at line 1"}
Я разместил запрос, ошибку и да, строки вставляются.
Хорошо, а как насчет "SELECT last_insert_id ();" в конце?





[Edit: добавлено "select" перед ссылками на last_insert_id ()]
А как насчет запуска "select last_insert_id();" после вставки?
MySqlCommand comm = connect.CreateCommand();
comm.CommandText = insertInvoice;
comm.CommandText += "\'" + invoiceDate.ToString("yyyy:MM:dd hh:mm:ss") + "\', "
+ bookFee + ", " + adminFee + ", " + totalFee + ", " + customerID + ");";
+ "select last_insert_id();"
int id = Convert.ToInt32(comm.ExecuteScalar());
Редактировать: Как упоминал Даффимо, вам действительно пригодятся параметризованные запросы как это.
Редактировать: Пока вы не переключитесь на параметризованную версию, вы можете найти мир со строкой.
comm.CommandText = string.Format("{0} '{1}', {2}, {3}, {4}, {5}); select last_insert_id();",
insertInvoice, invoiceDate.ToString(...), bookFee, adminFee, totalFee, customerID);
Я бы попробовал запрос без него. Действительно ли вставляются записи?
Хорошо, а как насчет "SELECT last_insert_id ();" в конце?
Майкл: last_insert_id () не является потокобезопасным. Если другой поток вставляет что-то, last_insert_id вернет последний вставленный идентификатор при подключении к базе данных. Поэтому, если это делают несколько потоков (или даже отдельные процессы с одним и тем же пользователем для db), это будет ошибочным.
Просто хотел отметить, что Тед прав, если отдельные потоки используют общее соединение. Если каждый поток устанавливает собственное соединение, он должен работать нормально, поскольку mysql обрабатывает его для каждого соединения. last_insert_id () документация
Меня беспокоит, что кто-то берет дату и хранит ее в базе данных как строку. Почему бы не сделать так, чтобы тип столбца отражал реальность?
Я также удивлен, увидев, что SQL-запрос строится с использованием конкатенации строк. Я разработчик Java и вообще не знаю C#, но мне было бы интересно, не было ли где-нибудь в библиотеке механизма привязки по строкам java.sql.PreparedStatement? Рекомендуется для защиты от атак с использованием SQL-инъекций. Еще одно преимущество - это возможное повышение производительности, поскольку SQL можно анализировать, проверять, один раз кэшировать и использовать повторно.
OP может использовать столбец даты в БД - мы не можем видеть эту часть. Я согласен с тем, что вам следует использовать параметризованные запросы. К счастью, это не похоже на то, что вы вставляете какой-либо текст, поэтому, строго говоря, вы, вероятно, в безопасности (хотя производительность может быть лучше).
Столбец на самом деле является датой, но если я попытаюсь вставить объект даты напрямую, у меня возникнут проблемы с его сбросом даты на набор нулей. Я новичок в C#, но я согласен с вами, вероятно, есть версия PreparedStatement для C#, и я изменю ее.
Если столбец действительно является датой, что делает этот вызов «toString» с шаблоном форматирования в коде?
Также относительно привязки: Odbc имеет механизмы привязки для mysql, см. dev.mysql.com/doc/connector-odbc/en/… и stackoverflow.com/questions/18082840/…
Фактически, метод ExecuteScalar возвращает первый столбец первой строки возвращаемого DataSet. В вашем случае вы делаете только Insert, вы на самом деле не запрашиваете какие-либо данные. Вам нужно запросить scope_identity () после вставки (это синтаксис SQL Server), и тогда вы получите свой ответ. Глянь сюда:
Обновлено: Как указал Майкл Харен, вы упомянули в своем теге, что используете MySql, используйте last_insert_id (); вместо scope_identity ();
Мой ответ включает версию scope_identity для Mysql в соответствии с тегами.
О, моя ошибка, я не заметил тег MySql. Отредактирую свой пост.
Нет проблем - я сам достаточно часто скучаю по ним.
Используйте LastInsertedId.
Просмотрите мое предложение с примером здесь: http://livshitz.wordpress.com/2011/10/28/returning-last-inserted-id-in-c-using-mysql-db-provider/
MySqlCommand comm = connect.CreateCommand();
comm.CommandText = insertStatement; // Set the insert statement
comm.ExecuteNonQuery(); // Execute the command
long id = comm.LastInsertedId; // Get the ID of the inserted item
Потрясающе .. Я даже не думал о том, что MysqlData будет это предоставлять. Отлично.
Возможно, cmd.LastInsertedId не является потокобезопасным ... но я предполагаю, что идентификатор извлекается в одном и том же вызове ExecuteNonQuery, а не в двух вызовах запроса, как в случае с SELECT LAST_INSERT_ID (). Возможно ли, что другой вызов из другого потока окажется «между» вставленной строкой и получением идентификатора. Я предполагаю, что сервер выполняет эту задачу и поэтому делает это немедленно. LAST_INSERT_ID потокобезопасен?
LastInsertedId возвращается немедленно с помощью cmd.executequery, поэтому я действительно не думаю, что другой поток может встать между этим. Но еще хотелось бы знать, чтобы быть уверенным на все 100%. Но по крайней мере мы знаем, что это безопасно от вставок других подключений
Похоже, это безопасно. См .: stackoverflow.com/a/30959730/711863
1. Можете ли вы опубликовать последний исполняемый CommandText? 2. Действительно ли вставляются записи?