2013-11-21 121 views
1

我有以下SP:C#SQL存儲過程 - 返回ID

ALTER Procedure [dbo].[SP_RegisterComp] 
    @CompName varchar(100) 
    ,@Check_In datetime 
    ,@ID int output 

As 
Set NoCount On 

Update Host Set [Check_In][email protected]_In 
       Where [CompName][email protected] 


If @@RowCount=0 
    Insert into Host values (@CompName, @Check_In) 
    SET @ID=SCOPE_IDENTITY() 
    RETURN @ID 

這工作得很好。如果表中已經存在計算機名稱,則更新檢入時間,否則將創建新記錄並返回該ID。

如何在更新記錄時獲取@id?

乾杯,

約翰

回答

1

你會設置一個Output參數。代碼可能是這樣的:

using (SqlConnection c = new SqlConnection(cString)) 
using (SqlCommand cmd = new SqlCommand("SP_RegisterComp", c)) 
{ 
    cmd.CommandType = CommandType.StoredProcedure; 

    cmd.Parameters.AddWithValue("@CompName", compName); 
    cmd.Parameters.AddWithValue("@Check_In", checkIn); 

    var outParm = new SqlParameter("@ID", SqlDbType.Int); 
    outParm.Direction = ParameterDirection.Output; 

    cmd.ExecuteNonQuery(); 

    var val = outParm.Value; 
} 

亞倫認爲,這是鎖定一個很好的候選人,交易程序始終是這裏的最佳實踐,以及。因此,修改後的代碼可能是這樣的:

lock (_lockObj) 
{ 
    using (SqlConnection c = new SqlConnection(cString)) 
    using (SqlTransaction tran = c.BeginTransaction()) 
    using (SqlCommand cmd = new SqlCommand("SP_RegisterComp", c, tran)) 
    { 
     cmd.CommandType = CommandType.StoredProcedure; 

     cmd.Parameters.AddWithValue("@CompName", compName); 
     cmd.Parameters.AddWithValue("@Check_In", checkIn); 

     var outParm = new SqlParameter("@ID", SqlDbType.Int); 
     outParm.Direction = ParameterDirection.Output; 

     cmd.ExecuteNonQuery(); 

     // commit the transaction 
     tran.Commit(); 

     var val = outParm.Value; 
    } 
} 

其中_lockObj被定義爲private object _lockObj = new Object();作爲一個字段。

注:你不需要在這裏擔心Rollback,因爲如果將引發異常的RollbackSqlTransaction對象的Dispose期間印發。

3

只要檢查行是否已經存在,而不是讓@@ROWCOUNT告訴你是否需要插入。

ALTER PROCEDURE [dbo].[SP_RegisterComp] 
    @CompName varchar(100) 
    ,@Check_In datetime 
    ,@ID int output 

AS 
SET NOCOUNT ON; 

SELECT TOP 1 @Id = [IdField] FROM Host WHERE [CompName] = @CompName 
    ORDER BY [Check_In] DESC 

IF (@Id IS NOT NULL) 
BEGIN 
    UPDATE Host SET [Check_In][email protected]_In WHERE [IdField] = @Id 
END 
ELSE 
BEGIN 

    INSERT INTO Host VALUES (@CompName, @Check_In) 
    SET @ID=SCOPE_IDENTITY() 

END 

RETURN @ID 
+0

您需要解決此交易,以防止競爭條件... –

0
  1. 你不需要它,然後,你送了它...
  2. 因爲你必須在發送它,它已經在@Id噸-SQL變量,這是一個輸出變量,以便它是在客戶端ado.net代碼

  3. 我喜歡以下模式訪問

    Alter Procedure [dbo].[SP_RegisterComp] 
        @CompName varchar(100), 
        @Check_In datetime. 
        @ID int = null 
        As 
        Set NoCount On 
    
        If @Id is null 
        Begin 
         Insert ... 
         SET @ID=SCOPE_IDENTITY() 
        End 
        Else Begin 
         Update ... 
         Where id = @Id 
        End 
    
        Select @Id id 
        Return 0 
    

然後在客戶端代碼中,在所有情況下,您將得到一個單行,單列結果集(一個ADO.Net表),其中包含id值。

+0

爽 - 感謝您的幫助 – user3015544

0

你應該檢查是否存在記錄:

If EXISTS (SELECT * FROM Host WHERE [CompName] = @CompName) 
    BEGIN 
     BEGIN TRAN 
      SELECT @ID=ID FROM Host WITH(UPDLOCK) 
      WHERE Comp_Name = @Comp_Name 

      UPDATE Host 
      SET [Check_In] = @Check_In 
      WHERE [Comp_Name] = @Comp_Name 
      RETURN @ID 
     COMMIT TRAN 
    END 
ELSE 
    BEGIN 
     Insert into Host values (@CompName, @Check_In) 
     SET @ID=SCOPE_IDENTITY() 
     RETURN @ID 
END 
+0

你需要一個交易,並可能暗示這裏可以防止兩張併發用戶輸入插入塊。你的SET行也有語法錯誤。 –