使用 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的主要内容,如果未能解决你的问题,请参考以下文章
执行 INSERT 到数据库获取插入行的 id 后如何获取?