Upsert Return ID

时间:2013-03-04 22:01:33

标签: c# sql-server

我正在尝试从存储过程中获取插入或更新的ID,我尝试了两种不同的方式

出于性能原因,我不允许使用If exists(select ....)

1-使用OUTPUT

    @firstName varchar(30),
    @Telephone int

        AS
        BEGIN transaction
            UPDATE [PHONE_BOOK].[dbo].[USER]
                       SET TELEPHONE= @Telephone
                       output inserted.USERID
                     where FIRST_NAME = @firstName

    if @@ROWCOUNT = 0
    begin
            INSERT INTO [PHONE_BOOK].[dbo].[USER]
           ([FIRST_NAME]
           ,[TELEPHONE])
           output inserted.USERID -- or output SCOPE_IDENTITY()
     VALUES
           (@firstName
           ,@Telephone)
  end

C#代码

IList<SqlParameter> parameters = new List<SqlParameter>();
            parameters.Add(new SqlParameter("@firstName", "Mike"));
            parameters.Add(new SqlParameter("@Telephone", 9514256));

            using (var sqlConnection = new SqlConnection(Config.ConnString))
            {
                sqlConnection.Open();
                using (SqlCommand command = sqlConnection.CreateCommand())
                {
                    command.CommandType = CommandType.StoredProcedure;
                    command.CommandText = "[dbo].[INSET_USER]";
                    command.UpdatedRowSource = UpdateRowSource.None;

                    foreach (SqlParameter oPar in parameters)
                        command.Parameters.Add(oPar);

                    object x = command.ExecuteScalar();

                }
            }
  1. 如果更新==&gt; x是正确的
  2. 如果删除==&gt; x为空
  3. 2-使用OUTPUT参数

    @firstName varchar(30),
    @Telephone int,
    @userId int output
    
    AS
    BEGIN transaction
        UPDATE [PHONE_BOOK].[dbo].[USER]
                   SET TELEPHONE= @Telephone
                 where FIRST_NAME = @firstName
                -- i can't find different way to set @userId than doing a select which is not acceptable
        if @@ROWCOUNT = 0
        begin
                INSERT INTO [PHONE_BOOK].[dbo].[USER]
               ([FIRST_NAME]
               ,[TELEPHONE])
         VALUES
               (@firstName
               ,@Telephone)
               set @userId = SCOPE_IDENTITY()
            end
    

    c#代码:

    IList<SqlParameter> parameters = new List<SqlParameter>();
                parameters.Add(new SqlParameter("@firstName", "Mike"));
                parameters.Add(new SqlParameter("@Telephone", 9514256));
    
                using (var sqlConnection = new SqlConnection(Config.ConnString))
                {
                    sqlConnection.Open();
                    using (SqlCommand command = sqlConnection.CreateCommand())
                    {
                        command.CommandType = CommandType.StoredProcedure;
                        command.CommandText = "[dbo].[INSET_USER]";
                        command.UpdatedRowSource = UpdateRowSource.None;
    
                        foreach (SqlParameter oPar in parameters)
                            command.Parameters.Add(oPar);
                        command.Parameters.Add("@userId",0).Direction = ParameterDirection.Output;
    
                        command.ExecuteNonQuery();
                        var x = command.Parameters["@userId"].Value;
    
                    }
                }
    
    1. 如果更新==&gt; x为-1
    2. 如果删除==&gt; x是正确的
    3. 我该如何解决这个问题?我提出第一个选项,因为我不需要将输出参​​数传递给存储过程

2 个答案:

答案 0 :(得分:0)

考虑使用RETURN或OUTPUT参数以及ExecuteNonQuery(),它会自动将值填充到变量中。不需要ExecuteScalar()。

http://blogs.msdn.com/b/spike/archive/2009/05/07/a-simple-example-on-how-to-get-return-and-out-parameter-values-using-ado-net.aspx

答案 1 :(得分:0)

在这种情况下你没有获得输出值的原因是因为你是*选择它而不是*返回它。如果你不想改变你的proc,你可以从第一个结果集中选择它 - 但是ExecuteScalar会抑制结果集,所以你会想要使用ExecuteReader或类似的东西。但是,有一个标准的模式,你没有遵循它,所以我会发布它只是为了好 - 我敢肯定它已被其他地方覆盖。

标准SP模式 -

create proc UpsertMyTable (
    @parameter int
) AS

declare @result int

if exists (select 1 from MyTable where value = @parameter) begin
    UPDATE HERE
end else begin
    INSERT HERE
end

set @result = SCOPE_IDENTITY()

return @result

然后在你的C#代码中,基本上你的示例中的内容是正确的,除了你完成参数的方式是多余的和性能问题......

using (var sqlConnection = new SqlConnection(Config.ConnString)) {
    sqlConnection.Open();
    using (SqlCommand command = sqlConnection.CreateCommand()) {
        command.CommandType = CommandType.StoredProcedure;
        command.CommandText = "[dbo].[PROC_UPSERT_SHARE]";
        command.UpdatedRowSource = UpdateRowSource.None;

        command.parameters.Add(new SqlParameter("@fullName", "dwfae"));
        command.parameters.Add(new SqlParameter("@name", "aze"));
        command.parameters.Add(new SqlParameter("@root", "aze"));
        command.parameters.Add(new SqlParameter("@creationDate", new DateTime(2000, 10, 10)));
        command.parameters.Add(new SqlParameter("@lastAccessDate", new DateTime(1999, 11, 11)));
        command.parameters.Add(new SqlParameter("@lastWriteDate", new DateTime(1990,12,12)));
        command.parameters.Add(new SqlParameter("@subShareCount", 20));
        command.parameters.Add(new SqlParameter("@serverId", "serverx"));

        object x = command.ExecuteScalar();
        Console.WriteLine(x);
    }
}

这样的事情会快得多。即使您认为影响可能很小,也请考虑这类事情。