Ответ 1
Существует перегрузка метода ExecuteSqlCommand
, который предотвращает это поведение:
db.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, sql, parameters);
Профилированный профилировщиком SQL Server: EF 6 завершает каждый вызов хранимой процедуры с помощью BEGIN TRAN
и COMMIT TRAN
.
Разве это не потрясающее изменение?
Возможно, это не только нарушение, но и невозможность любой транзакционной логики в SP, поскольку мы никогда не можем откатить нашу транзакцию в хранимой процедуре с помощью ROLLBACK TRAN
(обратите внимание: в SQL Server нет вложенных транзакций), поэтому один откаты отката до @@TRANCOUNT
ноль. Поскольку мы были в транзакции, потому что EF 6 мы получили "Счет транзакции после EXECUTE, указывает несоответствующее число операторов BEGIN и COMMIT. Предыдущий счет = 1, текущий счет = 0." стандартная ошибка SQL Server.
Пожалуйста, не спрашивайте меня, почему я хочу вызвать хранимые процедуры. У меня сотни, и все они используют логику TRY ... COMMIT ... CATCH ROLLBACK
.
Любые идеи, как я могу помешать EF 6 сделать это?
Существует перегрузка метода ExecuteSqlCommand
, который предотвращает это поведение:
db.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, sql, parameters);
В EF 6.1.2 флаг управляет поведением. Установка EnsureTransactionsForFunctionsAndCommands на false повлияет на SP, которые были импортированы в сущность (они вызывают функцию ExecuteFunction() внутри).
using (SomeEf6Context ctx = NewContext())
{
ctx.Configuration.EnsureTransactionsForFunctionsAndCommands = false;
// Call an imported SP
}
Настройка не повлияет на вызовы SaveChanges().
Как сказал crokusek, вы можете установить этот флаг для отключения транзакций для SP.
Если вы используете библиотеку Injection (DI) Dependency (DI), вы можете установить это следующим образом (я использую Simple Injector):
public partial class Startup
{
public Container ConfigureSimpleInjector(IAppBuilder app)
{
var container = new Container();
// Configure OWIN and Identity Framework
...
// Configure persistence
container.RegisterPerWebRequest<FakeDbContext>(() =>
{
var fakeDbContext = new FakeDbContext();
fakeDbContext.Configuration.EnsureTransactionsForFunctionsAndCommands = false;
return fakeDbContext;
}
// Register other services
...
container.Verify();
// For MVC
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
return container;
}
}
Просто для того, чтобы внести свой вклад, я сначала использую Unity как DI, EF 6.1.3 и базу данных, и я получаю сообщение: "Новая транзакция не разрешена, потому что в сеансе есть другие потоки" , когда я вызывал процедуру или функцию, отображаемую в моем файле edmx. Исправлена проблема с параметром EnsureTransactionsForFunctionsAndCommands = false. Решение Max Zerbini тоже работало, но я должен был бы использовать этот способ для каждого вызова процедуры.