使用 C# 获取插入行的 id

Posted

技术标签:

【中文标题】使用 C# 获取插入行的 id【英文标题】:Get the id of inserted row using C# 【发布时间】:2010-09-29 04:29:09 【问题描述】:

我有一个查询要在表中插入一行,该表有一个名为 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());

根据我的理解,这应该返回 ID 列,但它每次只返回 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"

【问题讨论】:

1.您可以发布最终执行的 CommandText 吗? 2. 记录真的被插入了吗? 我发布了查询,错误,是的,正在插入行。 好的,“SELECT last_insert_id();”怎么样最后? 【参考方案1】:
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

【讨论】:

LastInsertedId 不是线程安全的。 如果另一个线程正在插入东西,LastInsertedId 将返回连接到数据库的最后插入的 id。因此,如果多个线程执行此操作(或者甚至将具有相同用户的进程分开到 db),则会出现故障。 太棒了..我什至没有想到 MysqlData 会提供它。很棒。 这可能是 cmd.LastInsertedId 不是线程安全的......但我假设 ID 是在同一个 ExecuteNonQuery 调用中检索的,而不是像 SELECT LAST_INSERT_ID 那样的两个查询调用()。是否真的有可能来自另一个线程的另一个调用“介于”插入的行和检索 ID 之间。我猜服务器会执行此任务,因此会立即执行。 LAST_INSERT_ID 线程安全吗? LastInsertedId 立即与 cmd.executequery 一起返回,所以我真的不认为其他线程可以介于这两者之间。但我也想知道 100% 确定。但至少我们知道它不会受到其他连接插入的影响 似乎是安全的。见:***.com/a/30959730/711863【参考方案2】:

[编辑:在引用 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());

编辑:正如 duffymo 所提到的,使用参数化查询 like this 确实会为您提供很好的服务。


编辑:在您切换到参数化版本之前,您可能会发现使用 string.Format:

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();”怎么样最后? Michael:last_insert_id() 不是线程安全的。是另一个线程正在插入东西,last_insert_id 将返回最后插入的 id 与 db 的连接。因此,如果多个线程执行此操作(或者甚至将具有相同用户的进程分开到 db),则会出现故障。 只是想指出,如果各个线程使用共享连接,Ted 是正确的。如果每个线程都在建立自己的连接,它应该可以正常工作,因为 mysql 在每个连接的基础上处理它。 last_insert_id() documentation【参考方案3】:

使用 LastInsertedId。

在此处以示例查看我的建议:http://livshitz.wordpress.com/2011/10/28/returning-last-inserted-id-in-c-using-mysql-db-provider/

【讨论】:

【参考方案4】:

看到有人获取日期并将其作为字符串存储在数据库中,我感到很困扰。为什么不让列类型反映现实?

我也很惊讶地看到使用字符串连接构建 SQL 查询。我是一名 Java 开发人员,我根本不懂 C#,但我想知道库中的某处是否没有类似于 java.sql.PreparedStatement 的绑定机制?建议用于防范 SQL 注入攻击。另一个好处是可能的性能好处,因为 SQL 可以被解析、验证、缓存一次并重用。

【讨论】:

OP 可能正在使用数据库中的日期列——我们看不到那部分。不过,我同意您应该使用参数化查询。值得庆幸的是,您似乎没有插入任何文本,所以严格来说,您可能在这个上是安全的(尽管性能可能会更好)。 column 实际上是一个日期,但如果我尝试直接插入日期对象,我会遇到将日期重置为一组 0 的问题。我是 C# 新手,但我同意你的看法,可能有一个适用于 C# 的 PreparedStatement 版本,我会更改它。 如果该列确实是一个日期,那么使用代码中的格式化模式调用“toString”是什么? 另外关于绑定:Odbc 有 mysql 的绑定机制见dev.mysql.com/doc/connector-odbc/en/… 和***.com/questions/18082840/…【参考方案5】:

实际上,ExecuteScalar 方法返回正在返回的 DataSet 第一行的第一列。在你的情况下,你只是在做一个插入,你实际上并没有查询任何数据。您需要在插入后查询 scope_identity() (这是 SQL Server 的语法),然后您就会得到答案。见这里:

Linkage

编辑: 正如 Michael Haren 指出的,您在标签中提到您正在使用 MySql,请使用 last_insert_id();而不是 scope_identity();

【讨论】:

我的答案包括 Mysql 的 scope_identity 版本,根据标签。 哦,我的错,我没有注意到MySql标签。我会编辑我的帖子。 没问题——我自己也经常想念他们。

以上是关于使用 C# 获取插入行的 id的主要内容,如果未能解决你的问题,请参考以下文章

如何使用旧驱动程序获取 JDBC 中插入行的 ID?

执行 INSERT 到数据库获取插入行的 id 后如何获取?

如何在 MySQL 中获取多个插入行的 ID?

如何使用openxml获取新插入行的ID?

Android Room - 使用自动生成获取新插入行的 id - MVVM 版本

获取 SQLite 上最后插入行的 ID 的最佳方法