首页 > 解决方案 > 如果不存在,则插入 ELSE UPDATE SQL

问题描述

我究竟做错了什么?

我正在创建一个以数据库为中心的 Windows 窗体 C# 应用程序。在我的表单应用程序中,我有 4 个文本框,可将其数据插入到一个简单的数据库表中。

如果我在 textBox1(Customer_Name) 中输入一些内容,然后单击一个名为“检查并保存”的按钮,我希望该操作检查是否Customer_Name存在。

如果不存在,则应将数据插入数据库。

如果确实存在,它应该使用输入到 textBox1-4 的信息更新我的数据库

我有这个代码:

private void Button1_Click(object sender, EventArgs e)
{
    con.Open();

    SqlCommand cmd = new SqlCommand("IF NOT EXISTS (SELECT * FROM [Customers] WHERE Customer_Name=@aa BEGIN INSERT INTO [Customers](Customer_Name,Cellphone_Number,Telephone_Number,Alternative_Number) VALUES(@aa,@bb,@cc,@dd) END ELSE BEGIN UPDATE [Customers] SET Customer_Name=@aa, Cellphone_Number=@bb, Telephone_Number=@cc, Alternative_Number=@dd END", con);

    cmd.Parameters.AddWithValue("@aa", textBox1.Text);   
    cmd.Parameters.AddWithValue("@bb", textBox2.Text);  
    cmd.Parameters.AddWithValue("@cc", textBox3.Text);  
    cmd.Parameters.AddWithValue("@dd", textBox4.Text);

    con.Close();
}

单击按钮时不会将任何信息输入数据库,也不会更新任何信息。

标签: c#sql-server

解决方案


我究竟做错了什么?

您没有执行命令。一旦命令完全配置,
您的代码应该有一个。cmd.ExecuteNonQuery();

但是,一旦添加,您将收到来自 SQL Server 的语法错误消息。这是因为您缺少Exists运算符的右括号。

请注意,这远不是您在此代码中做错的唯一事情:

  1. 您将 UI 代码与应用程序代码混合在一起。
  2. 您正在使用全局变量(或至少是一个字段)来保存SqlConnection.
  3. 您为参数和 texboxes 使用了可怕的名称。
  4. 您正在使用AddWithValue.
  5. 您正在使用的“upsert”模式很麻烦并且可能存在问题。

以下是更好的选择:

首先
,您应该阅读有关n 层架构模式的内容。
对于 winform,通常使用MVP来实现。
一方面,不要将文本框数据直接发送到数据库,而是创建一个Customr类来保存数据,并使用它在代码中传递客户数据。

第二个
最佳实践是在 using 语句中使用局部变量,以确保处理SqlConnection实例并将底层连接返回到连接池。

第三
想象一下,必须在看起来像这样的代码中更改某些内容与在看起来像这样的代码中更改某些内容:

cmd.Parameters.Add(@"CustomerName", SqlDbType.NVarChar).Value = customerName;

现在,您无需阅读 SQL 即可了解该参数的含义——花在理解代码上的时间和精力越少越好。

第四
链接中的文章详细解释了为什么会出现问题,但重点是参数的数据类型必须从使用中推断出来,并且可能会因为数据类型错误推断出错误 - 甚至最坏 - 错误数据输入到数据库中。

第五
更好的模式是首先更新,然后有条件地插入 - 就像Aaron Bertrand 的回答中所展示的那样- 并在多用户(或多线程)环境中将整个事物包装在事务中。

话虽如此,修改后的代码应该看起来更像这样:

private void AddOrUpdateCustomer(Customer customer)
{
    // Data validity tests omitted for brevity - but you should ensure 
    // customer has all it's properties set correctly.

    // Readable, properly indented code - Isn't that much easier to debug?
    var sql = @"
        SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
        BEGIN TRANSACTION;
        UPDATE [Customers] 
        SET 
        Cellphone_Number = @Cell, 
        Telephone_Number = @Telephone, 
        Alternative_Number = @Alternative
        WHERE Customer_Name = @Name 

        IF @@ROWCOUNT = 0
        BEGIN 

        INSERT INTO [Customers](Customer_Name, Cellphone_Number, Telephone_Number, Alternative_Number) 
        VALUES(@Name, @Cell, @Telephone, @Alternative) 

        END
        COMMIT TRANSACTION;"; 


    // connectionString should be obtained from configuration file
    using(var con = new SqlConnection(connectionString))
    {
        using(var cmd = new SqlCommand(sql, con))
        {
            cmd.Parameters.Add(@"Name", SqlDbType.NVarChar).Value = customer.Name;
            cmd.Parameters.Add(@"Cell", SqlDbType.NVarChar).Value = customer.Cellphone;
            cmd.Parameters.Add(@"Telephone", SqlDbType.NVarChar).Value = customer.Telephone;
            cmd.Parameters.Add(@"Alternative", SqlDbType.NVarChar).Value = customer.AlternativeNumber;

            con.Open();
            cmd.ExecuteNonQuery();
        }
    }
}

推荐阅读