2015-11-24 40 views
4

總產值我有一個表中插入的記錄,並通過使用Output Inserted.KID返回IDENTITY列值這個存儲過程:如何從存儲過程獲得在asp.net

ALTER procedure [dbo].[InsertNode] 
(
    @FName nvarchar(50), 
    @Lname nvarchar(50), 
    @CDesc nvarchar(max), 
    @ParentID int 
) 
as 
begin 
    insert into Chart (FName , Lname ,CDesc, ParentID) 
    Output Inserted.KID 
    values (@FName, @Lname, @CDesc, @ParentID) 
end 

C#代碼:

public void InsertNode(string FName, string LName, string cDesc, int pid) 
{ 
    try 
    { 
     using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString)) 
     { 
      using (SqlCommand cmd = new SqlCommand("InsertNode", con)) 
      { 
       cmd.CommandType = CommandType.StoredProcedure; 
       cmd.Parameters.AddWithValue("@FName", FName); 
       cmd.Parameters.AddWithValue("@Lname", LName); 
       cmd.Parameters.AddWithValue("@CDesc", cDesc); 
       cmd.Parameters.AddWithValue("@ParentID", pid); 
       con.Open(); 
       Int32 retVal = cmd.ExecuteNonQuery(); 
      } 
     } 
    } 
    catch (Exception Ex) 
    { 
     Response.Write("ERROR: Unable to save data !!</br>" + Ex.Message); 
    } 

    Response.Write("Data Saved Successfully!"); 
} 

這是正確的方法和安全嗎?

現在,如何獲得存儲過程中的值爲OUTPUT asp.net(c#)?

+1

您需要使用'.ExecuteReader()'(而不是'.ExecuteNonQuery()')'的對象SqlCommand'自上現在執行此存儲過程返回一個結果設置 –

+2

你應該看看[我們可以停止使用AddWithValue()了嗎?](http://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/ ),並停止使用'.AddWithValue()' - 它可能會導致意想不到的結果和令人驚訝的結果... –

回答

6
string connectionString = ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString; 
string insertStoredProcName = "dbo.InsertNode"; 

using (SqlConnection conn = new SqlConnection(connectionString)) 
using (SqlCommand cmd = new SqlCommand(insertStoredProcName, conn)) 
{ 
    cmd.CommandType = CommandType.StoredProcedure; 

    -- set up paramters - DO NOT USE AddWithValue !!   
    cmd.Parameters.Add("@FName", SqlDbType.VarChar, 100).Value = FName; 
    cmd.Parameters.Add("@Lname", SqlDbType.VarChar, 100).Value = LName; 
    cmd.Parameters.Add("@CDesc", SqlDbType.VarChar, 100).Value = cDesc; 
    cmd.Parameters.Add("@ParentID", SqlDbType.Int).Value = pid; 

    conn.Open(); 

    using(SqlDataReader rdr = cmd.ExecuteReader()) 
    { 
     while (rdr.Read()) 
     { 
      -- read all returned values - if you only ever insert 
      -- one row at a time, there will only be one value to read 
      int insertedId = rdr.GetInt32(0); 
     } 

     rdr.Close(); 
    } 

    conn.Close(); 
} 
+1

只是好奇知道,我認爲''使用'封裝'連接'關閉和處置對象本身。然而,你仍然打電話給'conn.Close()' – Izzy

+0

@Izzy:是的 - 它確實 - 而且我仍然喜歡關於關閉的**顯式**。是的 - 「使用」塊將處理連接並在流程中關閉它 - 我只是將它用作**備份**而不是我關閉連接的主要方式(這同樣適用於「SqlDataReader」 ) - 我只使用''作爲安全網絡 - 而不是關閉閱讀器或連接的「正常」方式 –

+0

啊,對了,我得到你了......你讓我在那裏擔心,因爲我總是讓'使用'塊爲我處置連接 – Izzy

-1

如果您決定將來在表中添加觸發器,OUTPUT將會中斷。同樣,如果有多個插入,輸出將返回每個新插入行的ID。

或者如果是單個插入操作,則可以使用ExecuteScalar。

ALTER procedure [dbo].[InsertNode] 
(
    @FName nvarchar(50), 
    @Lname nvarchar(50), 
    @CDesc nvarchar(max), 
    @ParentID int 
) 
as 
begin 
    declare @KID int 

    insert into Chart (FName , Lname ,CDesc, ParentID) 
    values (@FName, @Lname, @CDesc, @ParentID) 

    SELECT @KID = SCOPE_IDENTITY(); 
end 

C#:

int KID = Convert.ToInt32(cmd.ExecuteScalar()); 
+0

如果你將'SCOPE_IDENTITY'賦給一個局部變量 - 結果集不會被返回給調用者,因此不能被讀取 - 這是** NOT **去工作!另外:如果你改變這個來處理**多行被一次插入,使用'ExecuteScalar()'將會中斷 - 'OUTPUT'仍然可以工作 –

+0

@marc_s原始問題顯示只有一個插入。 – niksofteng