【发布时间】:2008-12-01 12:37:49
【问题描述】:
我正在使用 SqlCommand 对象将记录插入到具有自动生成的主键的表中。如何编写命令文本,以便在使用 ExecuteScalar() 方法时获得新创建的 ID?
【问题讨论】:
-
如果您使用的是 Guid,请参阅我的回答。
标签: c# sql sql-server
我正在使用 SqlCommand 对象将记录插入到具有自动生成的主键的表中。如何编写命令文本,以便在使用 ExecuteScalar() 方法时获得新创建的 ID?
【问题讨论】:
标签: c# sql sql-server
INSERT INTO YourTable(val1, val2, val3 ...)
VALUES(@val1, @val2, @val3...);
SELECT SCOPE_IDENTITY();
不要忘记每条语句末尾的分号。
【讨论】:
将以下行添加到 Sql Query 的末尾...
SELECT SCOPE_IDENTITY()
然后在SqlCommand对象上使用ExecuteScalar方法……
var rowCount = command.ExecuteScalar()
【讨论】:
insert into Yourtable()
values()
SELECT SCOPE_IDENTITY()
我刚刚运行了一个测试,并使用 SQL Server 2005 SP2 和 .Net 3.5 验证了分号是可选的
【讨论】:
将输出参数添加到命令对象,然后将值设置为存储过程中的新 ID。
存储过程:
@ID AS INT OUTPUT
[Insert Command]
SET @ID = SCOPE_IDENTITY()
.NET:
cmd.CommandText = "stored_procedure";
SqlParameter pID = new SqlParameter("ID", DBType.Int32, 4);
pID.Direction = ParameterDirection.Output;
cmd.ExecuteScalar();
int id = Convert.ToInt32(cmd.Parameters["ID"].Value.ToString());
【讨论】:
不要使用@@IDENTITY,不管它看起来多么简单。它可能返回不正确的值。
SELECT SCOPE_IDENTITY()
似乎是显而易见的选择。
【讨论】:
虽然我喜欢Dave Markle's 答案,(我也看到你这样做了,因为你将它标记为你的答案),如果你的数据库上有触发器、审计 CUD 操作并且你的审计表有,那么该方法可能会失败IDENTITY 列。它将返回审计表的标识值,而不是您刚刚插入的表,因为审计表实际上是在之后发生的。
在这种情况下,可以使用更通用的方法,在这两种情况下都可以使用,而无需考虑任何审计。它有点罗嗦,但你得到了你付出的代价。
示例:
@"DECLARE @tmp AS TABLE ( id int )
INSERT INTO case
(
caseID,
partID,
serialNumber,
hardware,
software,
firmware
)
OUTPUT Inserted.ID into @tmp
VALUES
(
@caseID,
@partItemID,
@serialNumber,
@hardware,
@software,
@firmware
)
Select ID from @tmp" )
【讨论】:
在插入 stmt 后立即使用
SELECT CAST(scope_identity() AS bigint) ---- incase you have a return result as int64
这将返回创建的 id/identity 列。
【讨论】:
如果您的 id 是 Guid,那么我发现这个解决方案是最好的:
INSERT INTO YourTable (val1, val2, val3)
OUTPUT inserted.id
VALUES (@val1, @val2, @val3)
感谢@Scott Ivey
完整演示:
internal static Guid InsertNote(Note note)
{
Guid id;
using (
var connection =
new SqlConnection(ConfigurationManager.ConnectionStrings["dbconn"].ConnectionString))
{
connection.Open();
using (
var command =
new SqlCommand(
"INSERT INTO Notes ([Title],[Text]) " +
"OUTPUT inserted.id " +
$"VALUES ('{title}','{text}');", connection))
{
command.CommandType = CommandType.Text;
var reader = command.ExecuteReader();
reader.Read();
id = reader.GetGuid(reader.GetOrdinal("id"));
}
connection.Close();
}
return id;
}
我建议使用存储过程,但这是为了对我们的存储库进行单元测试。
【讨论】:
直接出Whirlpool:
如果您使用的是 MS SQL,您可以在插入后使用“SELECT @@IDENTITY as Value”来生成最后一个 ID
和:
@@IDENTITY和SCOPE_IDENTITY返回当前会话中任何表中生成的最后一个标识值。但是,SCOPE_IDENTITY只返回当前范围内的值;@@IDENTITY不限于特定范围。
编辑:正如 cmets 中所指出的,您应该始终使用 SCOPE_IDENTITY,而不是 @@IDENTITY。
【讨论】: