나는 거래를 조사해 왔으며, 내가 통과 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();
}
}
}