[C#] 트랜잭션 또는 SaveChanges (false) 및 AcceptAllChanges ()를 사용합니까?

나는 거래를 조사해 왔으며, 내가 통과 false하고 오류가없는 SaveChanges()한 전화 AcceptAllChanges()하는 한 EF에서 스스로 돌보는 것처럼 보입니다 .

SaveChanges(false);
// ...
AcceptAllChanges();

문제가 발생하면 어떻게합니까? 롤백하거나 내 방법이 범위를 벗어나 자마자 거래가 종료됩니까?

트랜잭션 중간에 할당 된 들여 쓰기 열은 어떻게됩니까? 광산이 나 빠지기 전에 다른 사람이 기록을 추가하면 ID 값이 누락 될 것입니다.

TransactionScope내 코드에서 표준 클래스 를 사용해야 할 이유가 있습니까?



답변

Entity Framework를 사용하면 대부분 SaveChanges()충분합니다. 그러면 트랜잭션이 생성되거나 주변 트랜잭션에 참여하고 해당 트랜잭션에 필요한 모든 작업이 수행됩니다.

때로는 SaveChanges(false) + AcceptAllChanges()페어링이 유용 하지만 .

가장 유용한 장소는 두 개의 다른 컨텍스트에서 분산 트랜잭션을 수행하려는 경우입니다.

즉 다음과 같은 것 (나쁜) :

using (TransactionScope scope = new TransactionScope())
{
    //Do something with context1
    //Do something with context2

    //Save and discard changes
    context1.SaveChanges();

    //Save and discard changes
    context2.SaveChanges();

    //if we get here things are looking good.
    scope.Complete();
}

경우 context1.SaveChanges()성공하지만 context2.SaveChanges()전체 분산 트랜잭션이 중단됩니다 실패합니다. 그러나 불행히도 Entity Framework는의 변경 사항을 이미 삭제 context1했기 때문에 실패를 재생하거나 효과적으로 기록 할 수 없습니다.

그러나 코드를 다음과 같이 변경하면

using (TransactionScope scope = new TransactionScope())
{
    //Do something with context1
    //Do something with context2

    //Save Changes but don't discard yet
    context1.SaveChanges(false);

    //Save Changes but don't discard yet
    context2.SaveChanges(false);

    //if we get here things are looking good.
    scope.Complete();
    context1.AcceptAllChanges();
    context2.AcceptAllChanges();

}

호출 SaveChanges(false)이 필요한 명령을 데이터베이스 에 전송하는 동안 컨텍스트 자체는 변경되지 않으므로 필요한 경우 다시 수행하거나 ObjectStateManager원하는 경우 질문 할 수 있습니다 .

즉, 트랜잭션이 실제로 예외를 발생시키는 경우 각 컨텍스트의 상태를 다시 시도하거나 로깅하여 ObjectStateManager어딘가에 보상 할 수 있습니다 .

자세한 내용은 블로그 게시물 을 참조하십시오 .


답변

EF6 (Entity Framework 6+)을 사용하는 경우 데이터베이스 호출이 SQL로 변경되었습니다.
참조 : http://msdn.microsoft.com/en-us/data/dn456843.aspx

context.Database.BeginTransaction을 사용하십시오.

MSDN에서 :

using (var context = new BloggingContext())
{
    using (var dbContextTransaction = context.Database.BeginTransaction())
    {
        try
        {
            context.Database.ExecuteSqlCommand(
                @"UPDATE Blogs SET Rating = 5" +
                    " WHERE Name LIKE '%Entity Framework%'"
                );

            var query = context.Posts.Where(p => p.Blog.Rating >= 5);
            foreach (var post in query)
            {
                post.Title += "[Cool Blog]";
            }

            context.SaveChanges();

            dbContextTransaction.Commit();
        }
        catch (Exception)
        {
            dbContextTransaction.Rollback(); //Required according to MSDN article 
            throw; //Not in MSDN article, but recommended so the exception still bubbles up
        }
    }
} 

답변

일부 데이터베이스는 dbContextTransaction.Commit ()에서 예외를 발생시킬 수 있으므로 다음과 같이하십시오.

using (var context = new BloggingContext())
{
  using (var dbContextTransaction = context.Database.BeginTransaction())
  {
    try
    {
      context.Database.ExecuteSqlCommand(
          @"UPDATE Blogs SET Rating = 5" +
              " WHERE Name LIKE '%Entity Framework%'"
          );

      var query = context.Posts.Where(p => p.Blog.Rating >= 5);
      foreach (var post in query)
      {
          post.Title += "[Cool Blog]";
      }

      context.SaveChanges(false);

      dbContextTransaction.Commit();

      context.AcceptAllChanges();
    }
    catch (Exception)
    {
      dbContextTransaction.Rollback();
    }
  }
} 


답변