14

私が理解できないことは、コンテキストを変更してコミットする前に同じトランザクションで変更を取得できるかどうかです。TransactionScopeをEntity Framework 6と併用する

これは - 私が探して何です:

using (var scope = new TransactionScope(TransactionScopeOption.Required)) 
{ 
    using (var context = new DbContext()) 
    { 
     //first I want to update an item in the context, not to the db 
     Item thisItem = context.Items.First(); 
     thisItem.Name = "Update name"; 
     context.SaveChanges(); //Save change to this context 

     //then I want to do a query on the updated item on the current context, not against the db 
     Item thisUpdatedItem = context.Items.Where(a=>a.Name == "Update name").First(); 

     //do some more query 
    } 

    //First here I want it to commit all the changes in the current context to the db 
    scope.Complete(); 
} 

誰かが私が作業パターンを理解し、私を見る助けることができますか?

答えて

29

はい、それは行うことは可能だとあなたが

using (var context = new DbContext())  
{ 
    using (var transaction = context.Database.BeginTransaction()) { 
     var item = new Item(); 
     context.Items.Insert(item); 
     context.SaveChanges(); // temporary insert to db to get back the auto-generated id 

     // do some other things 
     var otherItem = context.OtherItems.First(); 
     // use the inserted id 
     otherItem.Message = $"You just insert item with id = {item.Id} to database"; 
     transaction.Commit(); 
    } 
} 

をあなたの質問なので、データベースにエンティティを挿入し、次の挿入のためにに自動生成されたIDを使用するか、または更新したいときには非常に便利ですまた、作業パターンについて尋ねられましたが、ここで私の作業コード(FluentApi、DbContext &トランザクションの使用)があります。私はあなたと同じ問題を抱えていた:)。

var status = BeginTransaction() 
       // First Part 
       .DoInsert(entity1) 
       .DoInsert(entity2) 
       .DoInsert(entity3) 
       .DoInsert(entity4) 
       .SaveAndContinue() 
       // Second Part 
       .DoInsert(statusMessage.SetPropertyValue(message => message.Message, $"Just got new message {entity1.Name}")) 
      .EndTransaction(); 
+0

これはdbをローに挿入し、トランザクションがロールバックされるとローを削除しますか?または、行のIDをどのように取得しますか? @ kienct89 –

+0

transaction.Commit()を呼び出すまで、データベースに行を挿入しません。IDは一時的にメモリに割り当てられます –

+0

ok、例と説明ありがとうございます。私はこれを試して、あなたに戻ってきます –

2

あなたは、あなたのコンテキストのローカルコンテンツを照会していることを確認したい場合は、「ローカル」コレクションを使用することができます:これは、コンテキストと意志のメモリ内のデータを照会します

Item thisItem = context.Items.First(); 
thisItem.Name = "Update name";  
Item thisUpdatedItem = context.Items.Local.Where(a=>a.Name == "Update name").First(); 

をデータベースにヒットしません。
「ローカル」データは、コンテキスト内のオブジェクトを追加するか、データベースからロードする(つまり、SaveChanges()を呼び出す必要はありません)。
SaveChanges()はコンテキストの内容をデータベースに書き込みます。

+0

これは素晴らしいようだ:それは使用例あなた

public class FluentUnitOfWork : IDisposable { private DbContext Context { get; } private DbContextTransaction Transaction { get; set; } public FluentUnitOfWork(DbContext context) { Context = context; } public FluentUnitOfWork BeginTransaction() { Transaction = Context.Database.BeginTransaction(); return this; } public FluentUnitOfWork DoInsert<TEntity>(TEntity entity) where TEntity : class { Context.Set<TEntity>().Add(entity); return this; } public FluentUnitOfWork DoInsert<TEntity>(TEntity entity, out TEntity inserted) where TEntity : class { inserted = Context.Set<TEntity>().Add(entity); return this; } public FluentUnitOfWork DoUpdate<TEntity>(TEntity entity) where TEntity : class { Context.Entry(entity).State = EntityState.Modified; return this; } public FluentUnitOfWork SaveAndContinue() { try { Context.SaveChanges(); } catch (DbEntityValidationException dbEx) { // add your exception handling code here } return this; } public bool EndTransaction() { try { Context.SaveChanges(); Transaction.Commit(); } catch (DbEntityValidationException dbEx) { // add your exception handling code here } return true; } public void RollBack() { Transaction.Rollback(); Dispose(); } public void Dispose() { Transaction?.Dispose(); Context?.Dispose(); } } 

お役に立てば幸いです。一つの質問があります;彼の答えに記載されているkienct89のように、db内の自動ID生成を伴う挿入を処理します。 「ローカル」には同様の機能がありますか? –

+0

新しいレコードの場合「ローカル」は単なるステージング領域です。 IDは、レコードが挿入されたときにデータベースによって提供されます。 EF関数ではなく、データベース関数です。 –

関連する問題