2012-02-23 2 views
4

У меня есть проблема, которую я хотел бы поделиться. Контекст немного грязный, поэтому я постараюсь сделать все возможное в объяснении.Транзакционная операция с SaveChanges и ExecuteStoreCommand

Мне нужно создать транзакционную операцию над несколькими объектами. Я работаю с EF CodeFirst, но с устаревшей базой данных, которую я не могу изменить. Чтобы создать более согласованную модель, чем база данных, я проецирую информацию базы данных в более совершенные объекты, созданные мной самостоятельно.

Как мне нужно использовать разные контексты, моя первоначальная идея заключалась в использовании TransactionScope, который дал мне хорошие результаты в прошлом. Зачем мне нужны разные контексты? Из-за разнообразных проблем с db я не могу делать обновления только в одной операции (UnitOfWork). Мне нужно получить разные идентификаторы, которые появляются только после SaveChanges().

using (var scope = new TransactionScope()) 
{ 
    Operation1(); 
    Operation2(); 
    Operation3(uses ExecuteStoreCommand) 
    SaveChanges(); 

    Operation4(); 
    SaveChanges(); 
} 

Я знаю, что для того, чтобы использовать TransactionScope, мне нужно совместно использовать одно соединение между всеми операциями (И я делаю это, передавая контекст к объектам). Однако, когда я выполняю одну из операций (с использованием ExecuteStoreCommand), или я пытаюсь сделать некоторое обновление после первого SaveChanges, я всегда получаю ошибку MSDTC (поддержка распределенных транзакций отключена) или даже реже, так как выгружен домены.

Я не знаю, может ли кто-нибудь помочь мне, по крайней мере, знать, что это лучшее направление для этого сценария.

Спасибо большое,

+1

Похоже, что соединение связи открывает новые соединения под капотом. Возможно, вы сможете подключиться к [StateChange] (http://msdn.microsoft.com/en-us/library/system.data.common.dbconnection.statechange.aspx), чтобы получить более подробную информацию. –

+0

Если вы подключаетесь к различным базам данных (или используете Sql Server 2005), ваша транзакция продвигается к распределенной транзакции. Обратите внимание: если вы используете Sql Server 2005, транзакция автоматически продвигается к распределенной транзакции, поскольку EF будет открывать соединение более одного раза. Если вы хотите разделить одно и то же соединение между несколькими контекстами, вы должны открыть соединение внутри транзакции (это должно автоматически заручиться соединением в транзакции) и передать соединение с контекстом ctor. EF не закрывает соединение, которое оно не открыло. – Pawel

+0

Обратите внимание, что открытие соединения само по себе также является способом предотвращения продвижения транзакции к распределенной транзакции на Sql Server 2005, поскольку EF не закрывает и не открывает соединение. – Pawel

ответ

6

Посмотрите на этот ответ:
Entity Framework - Using Transactions or SaveChanges(false) and AcceptAllChanges()?
Ответ делает именно то, что вам требуется, имеющий транзакции, по нескольким контекстам данных.

Этот пост на Transactions and Connections in Entity Framework 4.0 Мне тоже очень помогли.

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

using (var dataContext = new ContextEntities()) 
{ 
    dataContext.Connection.Open(); 
    var trx = dataContext.Connection.BeginTransaction(); 

    var sql = "DELETE TestTable WHERE SomeCondition"; 
    dataContext.ExecuteStoreCommand(sql); 

    var list = CreateMyListOfObjects(); // this could throw an exception 
    foreach (var obj in list) 
     dataContext.TestTable.AddObject(obj); 
    dataContext.SaveChanges(); // this could throw an exception 

    trx.Commit(); 
} 
+0

Это была фантастическая информация, спасибо большое Ralph – IoChaos

+1

Соединение автоматически закрывается, когда контекст выпадает из области видимости, то есть в конце инструкции using. –

+0

спасибо, обновлено! –

Смежные вопросы