.NET SqlConnection и SqlCommand

Я использую классы SqlConnection и SqlCommand в своем проекте с Dapper ORM, но у меня возникла странная проблема. Когда я использую SqlCommand для вставки строки в таблицу БД, она всегда работает правильно, и когда я выбираю обновленные таблицы формы данных, все в порядке, но после закрытия внесенные мной изменения приложения не фиксируются, как данные были сохранены в каком-то кеше. Например, я создал простую таблицу только с двумя столбцами (UserId (PK) и UserName (Unique)) и даже в этом случае изменения не сохраняются. Я использую следующий код для вставки строки:

using (SqlConnection c = new SqlConnection(Settings.Default.UsersConnectionString))
        {
            c.Open();


            using (SqlCommand d = new SqlCommand())
            {
                d.CommandText = "INSERT INTO Users (UserName) VALUES ('SomeName')";
                d.CommandType = System.Data.CommandType.Text;
                d.Connection = c;
                int t = d.ExecuteNonQuery();
            }


            c.Close();
        }

person shadeglare    schedule 04.05.2011    source источник
comment
В стороне: c.Close(); row является избыточным, об этом позаботится внешнее предложение использования.   -  person Anders Fjeldstad    schedule 04.05.2011


Ответы (4)


Скорее всего, вы находитесь внутри незафиксированной транзакции. Возможно, Dapper ORM запустил транзакцию, и вы должны указать ему зафиксировать все изменения.

person Richard Schneider    schedule 04.05.2011
comment
Чтобы было понятно, я сделал простое консольное приложение только с одним кодом выше, но проблема та же. - person shadeglare; 04.05.2011

Предположительно, по умолчанию для вашего сервера установлено такое значение, что неявные транзакции были включены. Это означает, что если вы выполняете команду, а транзакция в данный момент не открыта, SQL Server автоматически запустит транзакцию (как всегда). Но когда команда завершается успешно, эта транзакция остается открытой и требует явной фиксации.

Чтобы определить, так ли это, попробуйте выполнить запрос @@OPTIONS :

IF @@OPTIONS & 2 > 0 
RAISERROR ('Implicit transactions are turned on', 1, 1)
person Damien_The_Unbeliever    schedule 04.05.2011

Этот код в dapper должен быть:

var name = "SomeName";
int t  = c.Execute("INSERT INTO Users (UserName) VALUES (@name)", new {name});

Dapper не управляет внутренними транзакциями, его необходимо передать с помощью необязательного параметра транзакции.

Моя кишка говорит мне, что вы подключаетесь к другой базе данных, чтобы вставить данные. Либо это неявные транзакции Дэмиена, которые легко проверить.

person Sam Saffron    schedule 05.05.2011
comment
Можно ли использовать Dapper для получения последнего вставленного идентификатора? - person jpshook; 18.07.2011
comment
c.Query<Decimal>("insert ... select SCOPE_IDENTITY()").First() .. не уверен, что numeric(38) точно соответствует int @Developr - person Sam Saffron; 18.07.2011
comment
Столбец My Identity в SQL имеет значение int. Независимо от того, что я установил для запроса Dapper (int, long и т. д.), он дает мне указанное приведение недействительно. исключение в строке Dapper: 1104 return (T) val; Нет ли способа сделать это с помощью execute, где я получаю его обратно в качестве выходного параметра, аналогично тому, как работает пример с хранимой процедурой? Не уверен, что это будет чище, но, по крайней мере, будет альтернативой. - person jpshook; 18.07.2011
comment
Кстати, недопустимое приведение было связано с тем, что SQL возвращал int как десятичное число! На данный момент я изменил c.Query‹decimal›, и он работает, хотя это немного неудобно. - person jpshook; 18.07.2011
comment
да, это десятичное число ... Dapper - это сторонник правильной настройки типов ... он не делает понижение или повышение по дизайну - person Sam Saffron; 18.07.2011
comment
так десятичный не ошибка? Было бы очень полезно, если бы вы могли сделать пример на странице Dapper о том, как это сделать. Кроме того, если есть способ сделать это в качестве выходного параметра, это было бы неплохо. - person jpshook; 18.07.2011
comment
Мне удалось заставить его работать с int, используя OUTPUT INSERTED.Id в моем SQL: вставить в имя таблицы (col1, col2) OUTPUT INSERTED.Id VALUES (@col1, @col2) - person jpshook; 18.07.2011

Возможно, база данных автоматически создает транзакцию, которая не фиксируется, попробуйте создать свою собственную транзакцию в коде и зафиксировать ее вручную и посмотреть, работает ли это.

using (SqlConnection c = new SqlConnection(Settings.Default.UsersConnectionString))
{
   c.Open();
   using (SqlTransaction t = c.BeginTransaction("InsertIntoUsers"))
   {
        using (SqlCommand d = new SqlCommand())
        {
            d.CommandText = "INSERT INTO Users (UserName) VALUES ('SomeName')";
            d.CommandType = System.Data.CommandType.Text;
            d.Connection = c;
            int t = d.ExecuteNonQuery();
        }
        t.Commit();
   }
}
person Manatherin    schedule 04.05.2011