استخدام المعاملات أو SaveChanges (كاذبة) وAcceptAllChanges ()؟

StackOverflow https://stackoverflow.com/questions/815586

سؤال

ولقد تم التحقيق المعاملات ويبدو أنهم الاعتناء بأنفسهم في EF طالما أمرر false إلى SaveChanges() ومن ثم استدعاء AcceptAllChanges() إذا كانت هناك أية أخطاء:

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

وماذا لو سارت الامور بشكل سيء؟ لا بد لي من العودة إلى الحالة السابقة، أو في أقرب وقت كما يقول لي طريقة للخروج من نطاق، هو الصفقة انتهت؟

وماذا يحدث لأية أعمدة indentiy التي تم تعيينها في منتصف الطريق من خلال المعاملة؟ أفترض إذا كان شخص آخر بإضافة سجل بعد الألغام قبل منجم ذهب سيئة فهذا يعني أنه سيكون هناك قيمة الهوية المفقودة.

هل هناك أي سبب لاستخدام فئة 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 في مكان ما.

بلدي <لأ href = "http://blogs.msdn.com/alexj/archive/2009 /01/11/savechanges-false.aspx "يختلط =" noreferrer "> بلوق وظيفة للحصول على أكثر من ذلك.

نصائح أخرى

إذا كنت تستخدم EF6 (الكيان الإطار 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(); 
    } 
  } 
} 
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top