title: One DbContext Instance spans multiple Repositories
body: <p>These are my AutoFac-DI definitions in my Web Api setup:</p>
  
  <pre><code> builder.RegisterType&lt;MyContext&gt;().As&lt;MyContext&gt;().InstancePerRequest();
   builder.RegisterType&lt;TestRepository&gt;().InstancePerRequest();
   builder.RegisterType&lt;SchoolclassCodeRepository&gt;().InstancePerRequest();
   builder.RegisterType&lt;TestService&gt;().InstancePerRequest();
  </code></pre>
  
  <p>The TestService constructor accepts the TestRepository and SchoolclassCodeRepository. Both Repositories accepts the same Instance of the MyContext.</p>
  
  <p><strong>I agree with this</strong>: <a href="https://stackoverflow.com/questions/14616211/is-it-wise-to-use-same-dbcontext-with-multiple-repositories">Is it wise to use same DbContext with multiple repositories?</a></p>
  
  <p><em>There are other good reasons to share a context though, one of which (IMHO) is that the context has to track the state of an entity, if you're get an entity, dispose the context, make some modifications to the entity, and then attach to a new context this new context has to go hit the database so it can figure out the state of the entity. Likewise if you're working with graphs of entities (Invoices, and all their InvoiceItems), then the new context would have to fetch all the entities in the graph to determine their state.</em></p>
  
  <p>But now I hit a one-way street with this architecture!</p>
  
  <p>What if I have to do a transaction spanning multiple repositories?</p>
  
  <p>With EF6 you do it like that without Repositories:</p>
  
  <pre><code>using(NorthwindEntities db = new NorthwindEntities())
  {
      DbContextTransaction transaction = db.Database.BeginTransaction();
  
      try
      {
          //insert record 1
          Customer obj1 = new Customer();
          obj1.CustomerID = "ABCDE";
          db.Customers.Add(obj1);
          db.SaveChanges();
  
          //insert record 2
          Customer obj2 = new Customer();
          obj2.CustomerID = "PQRST";
          db.Customers.Add(obj2);   
          db.SaveChanges();
  
          transaction.Commit();
      }
      catch
      {
          transaction.Rollback();
      }
  }
  </code></pre>
  
  <p>When I take now the above sample and try to do the same with my 2 repositories within the service, then I face a serious problem.</p>
  
  <ul>
  <li>I have no DbContext available in my Service.</li>
  <li>The DbContext is a DataProvider/Layer concern and should stay inside the repository.</li>
  </ul>
  
  <p>How can I create then a transaction over multiple repositories without changing my repositories?</p>
  
  <p>Sample what I want:</p>
  
  <p>Inside my TestService I want to do roughly:</p>
  
  <pre><code>public void Save()
  {
    // Open Transaction
    // testRepo.Insert();
    // schoolclassCodeRepo.Delete();
    // Commit Transaction
  }
  </code></pre>
  
  <p><strong>UPDATE</strong></p>
  
  <p>In my TestService I map all entities  from the repos to DTO objects which are then enriched by data + links (Rest) in my web api controllers.</p>
  
  <p><strong>UPDATE 2</strong></p>
  
  <ul>
  <li>The Repository pattern makes data access methods reusable thats good.</li>
  <li>But it makes a transaction over multiple repositories sharing same DbContext not possible.</li>
  </ul>
  
  <p>WOULD it not be better to implement all Repository methods as extension methods of the DbContext, this way I could call the "Repo extension methods" in my Service directly on the ONE DbContext injected into my TestService?</p>
  
  <p><strong>UPDATE 3 Solution code</strong></p>
  
  <pre><code>public async Task&lt;bool&gt; DeleteSchoolyearAsync(int id)
  {
      using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
      {
          try
          {
              await testRepository.DeleteTestTypes(id);
              await schoolyearRepository.DeleteAsync(id);
              scope.Complete(); // Rollback is done due to using statement...
              return true;
  
          }
          catch (System.Exception)
          {
              return false;
          }
      }
  }
  </code></pre>
  
  <p>This code worked fine!</p>