2008-10-09 53 views
13

我需要一个函数,它在数据库上执行INSERT语句并返回Auto_Increment主键。我有下面的C#代码,但是,虽然INSERT语句正常工作(我可以看到数据库中的记录,PK生成正确,行数为1),但id值始终为0.关于可能发生什么的任何想法错误?@@ IDENTITY INSERT语句总是返回0

public int ExecuteInsertStatement(string statement) 
    { 
     InitializeAndOpenConnection(); 
     int id = -1; 


     IDbCommand cmdInsert = connection.CreateCommand(); 
     cmdInsert.CommandText = statement; 
     int rows = cmdInsert.ExecuteNonQuery(); 

     if (rows == 1) 
     { 
      IDbCommand cmdId = connection.CreateCommand(); 
      cmdId.CommandText = "SELECT @@Identity;"; 
      id = (int)cmdId.ExecuteScalar(); 
     } 

     return id; 
    } 
    private void InitializeAndOpenConnection() 
    { 
     if (connection == null) 
      connection = OleDbProviderFactory.Instance.CreateConnection(connectString); 

     if(connection.State != ConnectionState.Open)     
      connection.Open(); 
    } 

在回答的答案,我想:

public int ExecuteInsertStatement(string statement, string tableName) 
    { 
     InitializeAndOpenConnection(); 
     int id = -1; 
     IDbCommand cmdInsert = connection.CreateCommand(); 
     cmdInsert.CommandText = statement + ";SELECT OID FROM " + tableName + " WHERE OID = SCOPE_IDENTITY();"; 
     id = (int)cmdInsert.ExecuteScalar(); 

     return id; 
    } 

但现在我得到的错误“人物SQL语句的结束后,发现”

我使用的MS Access数据库与OleDb连接,提供程序= Microsoft.Jet.OLEDB.4.0

+0

你能澄清你正在使用的数据库服务器,并可能对内嵌InitializeAndOpenConnection/connection.CreateCommand引用,因为它们可能会影响我们的答案您? :) – Rob 2008-10-09 10:00:54

+0

此外 - 整个“选择OID从x其中OID = SCOPE_IDENTITY()”瘦有点过于复杂,你说的(对于插入身份值为3的记录):“SELECT 3 FROM table_x WHERE 3 = 3“ - 有点多余 – Rob 2008-10-09 10:02:21

+0

@Rob:它可能看起来多余,但OID是键入int,其中scope_identity()不是,所以你可以直接抛出(int)cmd.ExecuteScalar() – devio 2008-10-09 13:03:50

回答

1

我认为你需要有与第一个创建命令选择@@身份 - 尝试追加它通过“; SELECT @@身份”和.ExecuteScalar theinsert语句

0

是否有你的表可能会被插入到其他表的触发器?通常我们建议不要使用@@ Identity来支持IDENT_CURRENT,这样您就可以保证返回的身份是针对您刚插入的表格。

+1

我想你应该使用SCOPE_IDENTITY,因为它返回当前会话和当前作用域中任何表生成的最后一个标识值,因此如果在插入表格后立即调用它,则可以保证获得正确的值。 – kristof 2008-10-09 09:57:07

+0

使用IDENT_CURRENT虽然指定了表名称,但不保证它在您的操作范围内,请参阅定义:“返回为指定的表或视图生成的最后一个标识值。生成的最后一个标识值可用于任何会话和任何范围“ – kristof 2008-10-09 09:58:37

+0

我认为要么有其缺点。从同一个表中获取“另一个”身份的机会与从同一个范围内的另一个表中获取身份类似。要么比@@身份好。 – 2008-10-09 10:35:07

0

我认为@@身份只有在命令的范围内是有效的 - 在你的情况,当你执行“声明”。

修改你的“声明”,让存储过程本身将在INSERT语句之后返回@@ IDENTITY值,并把它读作执行存储过程的返回码。

15

1)相结合的INSERT和SELECT语句(串联使用 “;”)到1分贝命令

2)使用SCOPE_IDENTITY()代替@@ IDENTITY

INSERT INTO ...布拉布拉; SELECT OID FROM表WHERE OID = SCOPE_IDENTITY()

- 更新:

因为它变成了该问题涉及到MS Access,我发现this article这表明简单地再次将第一命令和设定其CommandText到“SELECT @@ IDENTITY”就足够了。

-1

当你使用访问,看看this article从aspfaq,向下滚动到大约一半时的页面。代码采用传统的ASP,但希望这些原则仍然有效。


SELECT @@ Identity最终被视为单独的执行上下文,我相信。代码应该工作将是:

public int ExecuteInsertStatement(string statement) 
{ 
    InitializeAndOpenConnection(); 

    IDbCommand cmdInsert = connection.CreateCommand(); 
    cmdInsert.CommandText = statement + "; SELECT @@Identity"; 
    object result = cmdInsert.ExecuteScalar(); 

    if (object == DBNull.Value) 
    { 
     return -1; 
    } 
    else 
    { 
     return Convert.ToInt32(result); 
    } 
} 

你可能想/需要整理,虽然增加了“SELECT @@身份”到代码末端的串联。

4

你需要在同一时间,因为你打开初始连接返回身份。 从插入或输出变量中返回结果集。

你也应该使用SCOPE_IDENTITY()不@@的身份。Reference here

您应该添加

SELECT SCOPE_IDENTITY() 

插入之后。

0

检查您的数据库设置。我前段时间遇到类似问题,并发现SQL Server连接设置'no count'已启用。

在SQL Server Management Studio中,您可以通过右键单击对象资源管理器中的服务器,选择属性然后导航到连接页面来找到它。查看“默认连接选项”的设置

4

您正在使用Jet(不是SQL Server),Jet每个命令只能处理一条SQL语句,因此您需要在单独的命令中执行SELECT @@IDENTITY,显然确保它使用与INSERT相同的连接。

0

是不是大多数回答者忘记提问者没有使用SQL Server?

显然,MS Access 2000及更高版本 doesn't support @@IDENTITY另一种方法是“使用RowUpdated事件,您可以确定是否发生了INSERT,检索最新的@@ IDENTITY值,并将其放入DataSet中本地表的标识列中。”

是的,这是针对Access DB中的嵌入式VBA。这仍然可以通过访问对象库进行调用。

编辑:好吧,它是支持的,对于昏昏欲睡的清晨答案抱歉。但这个答案的其余部分可能会有所帮助。

7

Microsoft.Jet.OLEDB.4.0提供程序支持Jet v3和Jet v4数据库引擎,但 Jet @ v3不支持SELECT @@ IDENTITY。

MSAccess 97是Jet v3,不支持SELECT @@ IDENTITY;它支持MSAccess 2000及以上版本。

0

如果您想要检索您插入的交易的自动运行次数和您的环境的价值,请登录 1.数据库为MsAccess。 2.驱动是Jet4与这样的连接字符串 “提供者= Microsoft.Jet.OLEDB.4.0;密码= {0};数据源= {1};坚持安全信息=真” 3.使用OLEDB

您可以申请我的例子代码

OleDbConnection connection = String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Password={0};Data Source={1};Persist Security Info=True",dbinfo.Password,dbinfo.MsAccessDBFile); 
connection.Open(); 
OleDbTransaction transaction = null; 
try{ 
    connection.BeginTransaction(); 
    String commandInsert = "INSERT INTO TB_SAMPLE ([NAME]) VALUES ('MR. DUKE')"; 
    OleDbCommand cmd = new OleDbCommand(commandInsert , connection, transaction); 
    cmd.ExecuteNonQuery(); 
    String commandIndentity = "SELECT @@IDENTITY"; 
    cmd = new OleDbCommandcommandIndentity, connection, transaction); 
    Console.WriteLine("New Running No = {0}", (int)cmd.ExecuteScalar()); 
    connection.Commit(); 
}catch(Exception ex){ 
    connection.Rollback(); 
}finally{ 
    connection.Close(); 
} 
-2
CREATE procedure dbo.sp_whlogin 
(
@id nvarchar(20), 
@ps nvarchar(20), 
@curdate datetime, 
@expdate datetime 
) 

AS 
BEGIN 
DECLARE @role nvarchar(20) 
DECLARE @menu varchar(255) 
DECLARE @loginid int 

SELECT  @role = RoleID 
FROM   dbo.TblUsers 
WHERE UserID = @id AND UserPass = @ps 

if @role is not null 
BEGIN 
    INSERT INTO TblLoginLog (UserID, LoginAt, ExpireAt, IsLogin) VALUES (@id, @curdate, @expdate, 1); 
    SELECT @loginid = @@IDENTITY; 
    SELECT @loginid as loginid, RoleName as role, RoleMenu as menu FROM TblUserRoles WHERE RoleName = @role 
END 
else 
BEGIN 
    SELECT '' as role, '' as menu 
END 
END 
GO 
0

简短的回答:
1.创建每接受一个查询两个命令。
2.首先sql查询是INSERT记录。
3.第二个sql查询是“SELECT @@ Identity;”它返回自动编号。
4.使用cmd.ExecuteScalar()返回第一行的第一列。
5.返回的结果输出是在当前插入查询中生成的自动编号值。

It is referenced from this link。示例代码如下。请注意“SAME连接VS新连接”的区别。 SAME连接提供所需的输出。

class Program 
{ 
    static string path = @"<your path>"; 
    static string db = @"Test.mdb"; 
    static void Main(string[] args) 
    { 
     string cs = String.Format(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0}\{1}", path, db); 
     // Using the same connection for the insert and the SELECT @@IDENTITY 
     using (OleDbConnection con = new OleDbConnection(cs)) 
     { 
      con.Open(); 
      OleDbCommand cmd = con.CreateCommand(); 
      for (int i = 0; i < 3; i++) 
      { 
       cmd.CommandText = "INSERT INTO TestTable(OurTxt) VALUES ('" + i.ToString() + "')"; 
       cmd.ExecuteNonQuery(); 

       cmd.CommandText = "SELECT @@IDENTITY"; 
       Console.WriteLine("AutoNumber: {0}", (int)cmd.ExecuteScalar()); 
      } 
      con.Close(); 
     } 
     // Using a new connection and then SELECT @@IDENTITY 
     using (OleDbConnection con = new OleDbConnection(cs)) 
     { 
      con.Open(); 
      OleDbCommand cmd = con.CreateCommand(); 
      cmd.CommandText = "SELECT @@IDENTITY"; 
      Console.WriteLine("\nNew connection, AutoNumber: {0}", (int)cmd.ExecuteScalar()); 
      con.Close(); 
     } 
    } 
} 

这应该产生不言自明的输出:

AutoNumber: 1 <br> 
AutoNumber: 2 <br> 
AutoNumber: 3 <br> 

New connection, AutoNumber: 0