2008-10-09 127 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