استخدام المعاملات أو SaveChanges (كاذبة) وAcceptAllChanges ()؟
-
03-07-2019 - |
سؤال
ولقد تم التحقيق المعاملات ويبدو أنهم الاعتناء بأنفسهم في 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();
}
}
}