트랜잭션 또는 SaveChanges (False)를 사용하고 Acceptallchanges ()?
-
03-07-2019 - |
문제
나는 거래를 조사 해 왔으며 통과하는 한 그들이 EF에서 스스로 돌보는 것으로 보입니다. false
에게 SaveChanges()
그런 다음 전화하십시오 AcceptAllChanges()
오류가없는 경우 :
SaveChanges(false);
// ...
AcceptAllChanges();
뭔가 나빠지면 어떨까요? 롤백해야 할 필요가 없거나 내 메소드가 범위를 벗어나 자마자 거래가 종료 되었습니까?
거래를 통해 반쯤 할당 된 계약은 어떻게됩니까? 나는 다른 사람이 내 후에 내 후에 기록을 추가하면 나쁘게되기 전에 기록을 추가 한 경우, 이것은 신원 가치가 누락 될 것임을 의미합니다.
표준을 사용할 이유가 있습니까? TransactionScope
내 코드의 수업?
해결책
엔티티 프레임 워크와 함께 대부분 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()
전체 분산 트랜잭션이 중단됩니다. 그러나 불행히도 엔티티 프레임 워크는 이미 변경 사항을 폐기했습니다. 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();
}
}
}