Транзакции в LINQ to SQL

Мне нужна помощь в отношении транзакций из Linq в sql. Ниже представлен типичный макет транзакции. Если какая-либо операция не удалась, все операции откатываются.

mainTransaction (tScope)
     Operation 1 changes
     db.submitChanges()

     Operation 2 changes
     db.submitChanges()    
     ...

     catch(TransactionException ex)
         'rollback mainTransaction

     tScope.complete()

Однако я хотел бы иметь сценарий, в котором операция 2 должна иметь возможность видеть изменения от операции 1, и если какая-либо из операций завершится неудачно, все предыдущие операции должны быть отменены.

Я мог бы подумать о вложенных транзакциях в Linq to Sql, но, возможно, есть лучший способ. Я еще не пробовал подход вложенных транзакций.

mainTransaction
    childTransaction #1 
        child 1 changes

    childTransaction #2 changes
        should see child 1 changes
        child 2 changes

    childTransaction #3 changes
        should see child 1 changes
        should see child 2 changes
        child #3 changes

catch(TransactionException ex)
    'rollback child 1
    'rollback child 2
    ...
tScope.complete()

Обновление: допустим, у нас есть родительские и дочерние отношения. Родитель будет иметь ссылку на дочернюю коллекцию как parent.Childs EntitySet. Во всех операциях я передаю родительскую ссылку и выбираю дочерний EntitySet как parent.Childs. Я добавляю дочерние записи в таблицу Childs Linq, а не в Childs EntitySet. После операции №1 я выполняю db.submitChanges (). Для операции № 2 я не вижу вставленных записей операции № 1 в parent.Childs EntitySet даже после db.SubmitChanges (), но я вижу в таблице Child Linq. Есть идеи?

Я хочу сделать это с помощью Linq to Object. Linq to Object, похоже, не «видит» записи InsertOnSubmit в последующих операциях (например: если я вставляю запись в дочернюю таблицу, EntitySet, возвращенный из родительского отношения, не отображает вставленную запись).

Мне удалось добиться этого в Linq to SQL, но за счет повторного запроса всей таблицы Linq. Мне пришлось бы писать повторяющийся код для каждой операции.

Любые идеи? Пожалуйста, дайте мне знать, если вы придумаете более простой способ. Спасибо.


person hIpPy    schedule 23.04.2009    source источник
comment
Я не понимаю - операция 2 должна уже видеть результаты операции 1. Результаты операции 1 становятся видимыми после первого db.SubmitChanges (). Разве в вашем случае этого не происходит? Я неправильно понимаю проблему?   -  person Sander    schedule 24.04.2009
comment
Я обновил вопрос примером, выделенным курсивом, и пометил его как «обновление:».   -  person hIpPy    schedule 24.04.2009
comment
Я просто использую одну транзакцию и отслеживаю все записи для вставки в списки.   -  person hIpPy    schedule 01.08.2009


Ответы (2)


если размер данных каждой родительской таблицы достаточно управляем, я использовал список (linqToSqlRowType) для отслеживания популяции и добавления новых строк. поэтому я запросил список дочерних операций, где изменения еще не были отправлены.

Также в Linq to sql, возможно, и в linq to objects, вы можете установить поле строки внешнего ключа на еще не отправленную строку, и оно автоматически позаботится о любых полях идентификаторов.

person Maslow    schedule 27.08.2009

Уже поздно, но я хочу ответить на этот вопрос.

Вариант 1: с TransactionScope. Я не предпочитаю это.

// if an exception is thrown, ts.Complete() is not called causing rollback
using (TransactionScope ts = new TransactionScope())
{
    // operation 1 changes //
    var items = db.Items.ToList();
    var itemToFind = items.Where(somePredicate);
    db.Items.InsertOnSubmit(item1);
    db.Items.InsertOnSubmit(item2);
    db.SubmitChanges();

    // operation 2 changes //
    // re-query the table(s) again
    var items = db.Items.ToList();
    var itemToFind = items.Where(somePredicate);
    db.Items.InsertOnSubmit(item3);
    db.SubmitChanges()

    ts.Complete();
}

Вариант 2: посмотрите на context.GetChangeSet() Inserts, Updates или Deletes.

// operation 1 changes //
var items = db.Items.ToList();
var itemToFind = items.Where(somePredicate);
db.Items.InsertOnSubmit(item1);
db.Items.InsertOnSubmit(item2);
// do not submit changes here

// operation 2 changes //
// look in the ChangeSet
var itemToFind = items.Where(somePredicate);
if (itemToFind = null)
    itemToFind = db.GetChangeSet().Inserts.OfType<Item>().Where(somePredicate);
db.Items.InsertOnSubmit(item3);
db.SubmitChanges()    

// submit changes when all done
db.SubmitChanges();

Вариант 3: ведите отдельный список и просматривайте его (аналогично варианту 2).

// operation 1 changes //
var items = db.Items.ToList();
var itemToFind = items.Where(somePredicate);
db.Items.InsertOnSubmit(item1);
db.Items.InsertOnSubmit(item2);
customList.Add(item1);
customList.Add(item2);
// do not submit changes here

// operation 2 changes //
// look in the ChangeSet
var itemToFind = items.Where(somePredicate);
if (itemToFind = null)
    itemToFind = customList.Where(somePredicate);
db.Items.InsertOnSubmit(item3);
db.SubmitChanges()    

// submit changes when all done
db.SubmitChanges();

Я использовал варианты 2 и 3 в зависимости от ситуации, но избегал варианта 1.

person hIpPy    schedule 04.06.2013