Что я делаю не так?
Вы не выполняете команду.
Ваш код должен иметь cmd.ExecuteNonQuery();
после полной настройки команды.
Однако, как только вы добавите это, вы получите сообщение об ошибке синтаксиса от SQL Server.
Это потому, что вам не хватает закрывающей скобки для оператора Exists
.
Обратите внимание, что это далеко не единственное, что вы делаете неправильно в этом коде:
- вы смешиваете код пользовательского интерфейса с кодом приложения.
- вы используете глобальную переменную (или, как минимум, поле) для хранения вашего экземпляра
SqlConnection
.
- вы используете ужасные имена для ваших параметров и текстовых полей.
- Вы используете
AddWithValue
.
- шаблон для "upsert", который вы используете, громоздок и потенциально проблематичен.
Вот лучшие альтернативы:
Первый
Вам следует прочитать о n-уровневом архитектурном шаблоне .
Для winforms это обычно реализуется с использованием MVP .
Во-первых, вместо отправки данных текстовых полей непосредственно в базу данных, создайте класс Customr
для хранения данных и используйте его для передачи данных клиента в вашем коде.
Второй
Рекомендуется использовать локальную переменную внутри оператора using для обеспечения удаления экземпляра SqlConnection
и возврата базового соединения в пул соединений.
Третий
Представьте, что вам нужно что-то изменить в коде, похожем на это, или изменить что-то в коде, который выглядит так:
cmd.Parameters.Add(@"CustomerName", SqlDbType.NVarChar).Value = customerName;
Теперь вам не нужно читать SQL, чтобы понять, что означает этот параметр -
чем меньше времени и усилий вы потратите на понимание кода, тем лучше.
Четвертый
Статья в ссылке объясняет, почему это проблематично,
но главное в том, что тип данных параметра должен быть выведен из использования,
и это может привести к ошибкам из-за неверно выведенного типа данных или, что еще хуже, неверно введенных в базу данных данных.
Пятый
Лучше всего сначала обновить, а затем вставить условно - как показано в ответе Аарона Бертранда - и в многопользовательской (или многопоточной) среде обернуть все в транзакции.
При всем этом, пересмотренный код должен выглядеть примерно так:
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();
}
}
}