2009-01-02 11 views
18

Ich habe eine Abfrage zum Einfügen einer Zeile in eine Tabelle, die ein Feld namens ID hat, die mit einem AUTO_INCREMENT für die Spalte aufgefüllt wird. Ich brauche diesen Wert für die nächste Bit-Funktionalität zu erhalten, aber wenn ich folgendes ausführen, es gibt immer 0, obwohl der tatsächliche Wert nicht 0:Holen Sie die ID der eingefügten Zeile mit C#

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()); 

Nach meinem Verständnis sollte dies die ID zurückkehren Spalte, aber es gibt nur 0 jedes Mal zurück. Irgendwelche Ideen?

EDIT:

Wenn ich laufen:

"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();" 

ich:

{"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"} 
+0

1. Können Sie die endgültige Command schreiben, die ausgeführt wird? 2.Werden die Datensätze tatsächlich eingefügt? –

+0

Ich habe die Abfrage, den Fehler, und ja, die Zeilen werden eingefügt. – Elie

+0

OK, wie wäre es mit "SELECT last_insert_id();" Am Ende? –

Antwort

15

[Edit: added "wählen Sie" vor Referenzen() LAST_INSERT_ID]

Was ist mit dem Laufen "select last_insert_id();" nach Ihrer Eingabe t?

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()); 

Edit: Wie duffymo erwähnt, würden Sie wirklich gut like this mit parametrisierte Abfragen bedient werden.


Edit: Bis Sie eine parametrisierte Version wechseln, Sie Frieden mit string.Format finden könnten:

comm.CommandText = string.Format("{0} '{1}', {2}, {3}, {4}, {5}); select last_insert_id();", 
    insertInvoice, invoiceDate.ToString(...), bookFee, adminFee, totalFee, customerID); 
+0

Ich würde die Abfrage ohne es versuchen. Werden die Datensätze tatsächlich eingefügt? –

+0

Ja, die Datensätze werden eingefügt. – Elie

+0

OK, wie wäre es mit "SELECT last_insert_id();" Am Ende? –

0

Es stört mich jemand zu sehen ein Date zu nehmen und es in einem Speicher Datenbank als String. Warum sollte der Säulentyp nicht die Realität widerspiegeln?

Ich bin auch überrascht zu sehen, dass eine SQL-Abfrage mit String-Verkettung aufgebaut wird. Ich bin ein Java-Entwickler und ich kenne C# überhaupt nicht, aber ich würde mich fragen, ob es irgendwo in der Bibliothek einen Bindemechanismus in der Art von java.sql.PreparedStatement gäbe. Es wird empfohlen, SQL-Injection-Angriffen vorzubeugen. Ein weiterer Vorteil sind mögliche Leistungsvorteile, da das SQL-Protokoll analysiert, verifiziert, einmal zwischengespeichert und wiederverwendet werden kann.

+0

OP könnte eine Datumsspalte in der DB verwenden-- Wir können diesen Teil nicht sehen. Ich stimme zu, dass Sie jedoch parametrisierte Abfragen verwenden sollten. Glücklicherweise sieht es nicht so aus, als würden Sie irgendeinen Text einfügen, also sind Sie wahrscheinlich streng sicher (obwohl die Leistung besser sein könnte). –

+0

Spalte ist eigentlich ein Datum, aber wenn ich versuche, das Datum Objekt direkt einfügen, hatte ich Probleme mit dem Zurücksetzen des Datums auf eine Reihe von 0s. Ich bin neu in C#, aber ich stimme dir zu, es gibt wahrscheinlich eine Version von PreparedStatement für C#, und ich werde das ändern. – Elie

+0

Wenn die Spalte tatsächlich ein Datum ist, wie lautet der "toString" -Aufruf mit dem Formatierungsmuster im Code? – duffymo

0

Tatsächlich gibt die ExecuteScalar-Methode die erste Spalte der ersten Zeile des zurückgegebenen DataSets zurück. In Ihrem Fall erstellen Sie nur einen Insert, Sie fragen tatsächlich keine Daten ab. Sie müssen die scope_identity() nach dem Einfügen abfragen (das ist die Syntax für SQL Server) und dann haben Sie Ihre Antwort. Siehe hier:

Linkage

EDIT: Als Michael Haren wies darauf hin, die Sie erwähnt in Ihrem Tag Sie verwenden MySQL, verwenden LAST_INSERT_ID(); anstelle von scope_identity();

+0

Meine Antwort enthält die scope_identity-Version für Mysql, wie die Tags. –

+0

Oh, mein Fehler, ich habe das MySql-Tag nicht bemerkt. Ich werde meinen Beitrag bearbeiten. – BFree

+0

Kein Problem - ich vermisse sie oft genug selbst. –

32
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 
+4

* LastInsertedId ist nicht threadsicher. * Wenn ein anderer Thread Dinge einfügt, gibt LastInsertedId die letzte eingefügte ID auf der Verbindung zur Datenbank zurück. Wenn es also mehrere Threads tun (oder sogar Prozesse mit demselben Benutzer zur db trennen), wird es fehlerhaft sein. – Ted

+0

Awesome .. Ich habe sogar nicht darüber nachgedacht, dass MysqlData es bereitstellen würde. groß. – Sami

+1

Es kann sein, dass cmd.LastInsertedId nicht threadsicher ist ..... aber ich nehme an, die ID wird im selben ExecuteNonQuery-Aufruf abgerufen, nicht in zwei Abfrageaufrufen, wie Sie es mit SELECT LAST_INSERT_ID() tun müssen. Ist es wirklich möglich, dass ein anderer Aufruf von einem anderen Thread "zwischen" die eingefügte Zeile und das Abrufen der ID gelangt. Ich schätze der Server macht diese Aufgabe und tut es daher sofort. Ist LAST_INSERT_ID Thread sicher? – MrCalvin