2015-10-14 3 views
0

У меня есть два класса. Первый представляет собой основные данные, второй представляет его подробные данные (они связаны через внешние ключи). Поскольку для записи подробных данных требуется существующая основная запись, сначала необходимо сохранить основную запись. К сожалению, ошибки могут возникать при сохранении подробных данных, поэтому я должен откатить сохранение мастера и в случае ошибки.Как использовать комбинированные транзакции в Entity Framework 6

У меня есть следующий код.

Мастер-класс:

MyDataContext db=new MyDataContext(); 
DetailData detail=new DetailData(); 
using (var transaction= db.Database.BeginTransaction()) 
{ 
    try 
    { 
    //db.Database.CommandTimeout = 10; 
    db.SaveChanges(); 
    //saving details 
    detail.SaveData(masterId); 
    //on success 
    transaction.Commit(); 
    } 
    catch (Exception) 
    { 
    transaction.Rollback(); 
    throw; 
    } 
} 

Подробный класс:

MyDataContext db; 
DataItem dataItem; 

public DetailData() 
{ 
db=new MyDataContext(); 
dataItem=new DataItem(); 
db.DataItem.Attach(dataItem); 
} 

public SaveData(int id) 
{ 
    dataItem.Master_ID=id; 
    db.SaveChanges(); 
} 

Как это best practice by Microsoft использовать DataContext по требованию, я не хочу, чтобы передать существующий контекст в подробных данных.

В общем случае экземпляр DataContext рассчитан на то, чтобы продлиться один «блок работы», однако ваше приложение определяет этот термин. DataContext легкий и не дорогой в создании. Типичное приложение LINQ to SQL создает экземпляры DataContext в области методов или как член краткосрочных классов , которые представляют собой логический набор связанных операций базы данных .

К сожалению, я получаю исключение в таймаута как основной сделки пока не совершил, и я начинаю новый SaveChanges на другом объекте контекста.

Если я использую db.DataBase.UseTransaction и передаю транзакцию мастер-класса, я получаю другое исключение из-за транзакции , принадлежащей другому контексту.

Итак, как я могу объединить сохранение данных мастера и детали в одну рабочую транзакцию?

+0

Если ваши объекты связаны внешним ключом, и это отношение известно EF, то почему вы не можете просто добавить 'Detail' в' Master' и вызвать 'SaveChanges'? EF сделает для вас тяжелую работу (он будет делать обновления в правильном порядке и помещает все это в транзакцию)? –

+0

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

ответ

1

Может быть, я неправильно ваш вопрос, или, возможно, следующая картина не возможно в вашей ситуации, но в целом вы можете добавить мастер/подробные записи, как так:

var customer = new Customer(); 
dbContext.Customers.Add(customer); 

var order = new Order(); 
order.Customer = customer; 

dbContext.SaveChanges(); 

Это предполагает, что ваши Customer и Order таблицы связанных с внешним ключом, и с подходящими свойствами навигации EF (например, order.Customer).

Entity Framework добавит Customer и Order записей в правильном порядке, а также ко всему обновлению внутри транзакции, так что оба обновления будут успешными, либо нет.


UPDATE: Если у вас есть два контекста, каждый из них будет не знать об изменениях, сделанных с другой - и если вы пытаетесь добавить объект из одного контекста в другой контекст, вы получите ошибку ,

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

К котировке, которую вы добавили на свой вопрос, говорится о единицах работы. Ваша единица работы должна логически включать все изменения, которые вы делаете, как на главную, так и на подробную запись. В этом весь смысл. У вас должен быть только один контекст! :-) Но вы можете создать транзакцию в пределах того контекста.

+0

Отданный контекст задается, так как деталь отвечает за другие операции, поэтому он также будет использовать другие SaveChanges, которые не должны мешать его хозяину. Поэтому я должен _комбинация_ каким-то образом отделенным контрессом, следовательно, названием. – Nestor

+0

@ Нестор: см. Мое обновление. –

+0

Я склоняюсь к созданию единого контекста ... для этого требуется много испытаний. Если я начну транзакцию и вызову многие 'SaveChanges', они будут выполняться только в Commit, правильно? – Nestor

1

Если я правильно понял, ваш мастер-класс пытается выполнить две задачи: представить запись основных данных и управлять ее сохранением. То же самое для класса Detail. Таким образом, борьба с принципом разделения проблем таким образом может вызвать такие проблемы.

Использование шаблонов репозитория и единицы работы поможет вам отделить объекты от логики управления транзакциями. См. Tom Dykstra's excellent tutorial в шаблонах репозитория и единицы работы в MVC.

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