كما ذكرنا سابقًا، تقوم عناصر التحكم المرتبطة بالبيانات بتخزين القيم التي تم تمريرها إلى مصدر البيانات في مفاتيح مستقلة وقيم (قيم جديدة) وقواميس OldValues. افتراضيًا، يتجاهل SqlDataSource وObjectDataSource حقل OldValues ويستخدمون المفاتيح والقيم فقط. تم الكشف عن هذا السلوك بواسطة خاصية ConflictDetection الخاصة بمصدر البيانات، والتي تم تعيينها إلى OverwriteChanges بشكل افتراضي. يعني نمط OverwriteChanges "مطابقة قيمة المفتاح الأساسي فقط لتحديث السجل أو حذفه". تعني هذه العملية أن تحديث السجل أو حذفه لا يأخذ في الاعتبار ما إذا كانت القيمة الأساسية للسجل قد تغيرت. في الظروف العادية، تكون الحالة المثالية هي السماح بنجاح عملية التحديث أو الحذف فقط عندما تتطابق قيمة صف البيانات تمامًا مع القيمة المحددة في الأصل. في هذا الوضع المثالي، إذا قام مستخدم آخر بتحديث صف بين الوقت الذي حددته فيه والوقت الذي قمت فيه بتحديثه، فستفشل عملية التحديث. يدعم مصدر البيانات أيضًا هذه العملية عن طريق تعيين خاصية ConflictDetection إلى CompareAllValues. في هذا الوضع، سيقوم مصدر البيانات بتطبيق OldValues على الأمر أو الطريقة، وسيستخدم هذه القيم للتأكد من أن عملية التحديث أو الحذف يجب أن تتطابق مع جميع قيم السجل قبل تحديث أو حذف سِجِلّ. يجب عليك أيضًا تعيين خاصية OldValuesParameterFormatString إلى سلسلة تنسيق مكون .NET Framework صالحة (مثل "original_{0}") للإشارة إلى كيفية إعادة تسمية المعلمات في قواميس OldValues وKeys لتمييزها عن معلمات NewValues.
يوضح مثال التعليمات البرمجية التالي أوامر SQL النموذجية التي يستخدمها عنصر التحكم SqlDataSource في وضعي OverwriteChanges وComparAllValues. من المفترض أن يكون حقل المعرف هو حقل المفتاح الأساسي. لاحظ أن الأمر الأخير يقارن جميع القيم الأولية لصفوف البيانات في جملة WHERE، بدلاً من المفاتيح الأساسية فقط. في هذه الحالة، يجب تعيين OldValuesParameterFormatString لمصدر البيانات إلى "original_{0}".
اختر [المعرف]، [الاسم]، [العنوان] من [جهات الاتصال]
- الكتابة فوق التغييرات
تحديث [جهات الاتصال] تعيين [الاسم] = @الاسم، [العنوان] = @العنوان حيث [المعرف] = @ID
احذف من [جهات الاتصال] حيث [المعرف] = @ID
- CompareAllValues
تحديث [جهات الاتصال] تعيين [الاسم] = @الاسم، [العنوان] = @العنوان حيث [المعرف] = @original_ID
و[الاسم] = @original_Name و[العنوان] = @original_Address
احذف من [جهات الاتصال] حيث [المعرف] = @original_ID و[الاسم] = @original_Name
AND [Address] = @original_Address
يرجى ملاحظة أن القيم القديمة ليست مطلوبة لعمليات الإدراج، وأن ConflictDetection مفيد فقط لعمليات التحديث والحذف.
يوضح المثال التالي السلوك عند حدوث تعارض. لتشغيل هذا المثال، يجب عليك فتح مثيلين للمثال في نافذتي متصفح منفصلتين (انقر فوق "تشغيل النموذج" مرتين). ثم انقر فوق الزر "تحرير" الموجود في نفس الصف في كلا النموذجين لوضع الصف في وضع التحرير. قم بتغيير القيمة في النافذة الأولى وانقر فوق "تحديث". يرجى ملاحظة أن التحديث كان ناجحًا. في النافذة الثانية، أدخل قيمة جديدة في الصف وانقر فوق "تحديث". لم تكن عملية التحديث هذه ناجحة لأن قيمة صف البيانات الأساسي قد تم تغييرها بالفعل من خلال عملية التحديث الأولى. يتحقق هذا المثال من خاصية AffectedRows لمعلمة الحدث المحدثة أو المحذوفة، والتي تكون قيمتها 0 للتأكد من حدوث تعارض.
< تشغيل البرنامج النصي = "الخادم">
SqlDataSource1_Updated الفرعي المحمي (المرسل ككائن، e كـ SqlDataSourceStatusEventArgs)
إذا كان e.AffectedRows = 0 إذن
Response.Write("تم تغيير الصف، وتم إحباط التحديث<br />")
نهاية إذا
النهاية
الفرعية المحمية SqlDataSource1_Deleted (المرسل ككائن، e كـ SqlDataSourceStatusEventArgs)
إذا كان e.AffectedRows = 0 إذن
Response.Write("تم تغيير الصف، وتم إحباط الحذف<br />")
نهاية إذا
نهاية الفرعية
</script>
عندما يستخدم التحديث أو الحذف واجهة المستخدم القالبة، سيتم الاحتفاظ بالقيم القديمة لحقول ربط البيانات ثنائية الاتجاه باستخدام بناء جملة Bind. بالنسبة للحذف، هذا يعني أنه يجب عليك استخدام بناء جملة Bind للقيم المرتبطة بالبيانات في ItemTemplate. والغرض من ذلك هو الاحتفاظ بالقيمة القديمة المطلوبة لعملية الحذف. يوضح المثال التالي هذه التقنية.
<asp:GridView……>
<الأعمدة>
<asp:CommandField ShowDeleteButton = "True" ShowEditButton = "True" />
<asp:TemplateField HeaderText="ContactID" InsertVisible="False" SortExpression="ContactID">
<قالب العنصر>
<asp:Label ID="Label1" runat="server" Text='<%# Bind("ContactID") %>'></asp:Label>
</قالب العنصر>
<تحرير قالب العنصر>
<asp:Label ID="Label3" runat="server" Text='<%# Eval("ContactID") %>'></asp:Label>
</EditItemTemplate>
</asp:حقل القالب>
<asp:TemplateField HeaderText="ContactName" SortExpression="ContactName">
<قالب العنصر>
<asp:Label ID="Label2" runat="server" Text='<%# Bind("ContactName") %>'></asp:Label>
</قالب العنصر>
<تحرير قالب العنصر>
<asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("ContactName") %>'></asp:TextBox>
</EditItemTemplate>
</asp:حقل القالب>
</الأعمدة>
</asp:GridView>
يمكنك التعامل مع أخطاء الكشف عن التعارض بلطف عن طريق مطالبة المستخدم بتغيير البيانات الأساسية وعرض القيمة المتغيرة للمستخدم والسماح للمستخدم باختيار إرسال العملية أو التخلي عنها. يوضح المثال التالي إحدى الطرق الممكنة لمعالجة الكشف عن التعارض. لاحظ أن معلمة الحدث RowUpdated الخاصة بـ DateView يتم تمريرها إلى قاموس يمكن استخدامه للكشف عن القيم التي يدخلها المستخدم. يمكنك أيضًا تعيين خاصية KeepInEditMode لمعلمة الحدث هذه لإبقاء عرض التفاصيل في وضع التحرير بينما يقرر المستخدم كيفية التعامل مع التعارض. يختبر هذا المثال أسلوبًا مشابهًا للمثال السابق، حيث يفتح نافذتين في وقت واحد لإنشاء تحديثات متعارضة.
التفاصيل الفرعية المحميةView1_ItemUpdated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DetailsViewUpdatedEventArgs)
إذا كان e.AffectedRows = 0 إذن
' ضع عرض التفاصيل في وضع التحرير وقم بمزامنته مع قاعدة البيانات e.KeepInEditMode = True
تفاصيلView1.DataBind ()
'أعد ملء عرض التفاصيل بالقيم التي أدخلها المستخدم
تعتيم كمربع نص
t = التفاصيلView1.Rows(1).الخلايا(1).Controls(0)
t.Text = e.NewValues("OrderDate")
t = تفاصيلView1.Rows(2).Cells(1).Controls(0)
t.Text = e.NewValues("ShipCountry")
ErrorPanel.Visible = True
آخر
ErrorPanel.Visible = خطأ
نهاية إذا
من النهاية الفرعية
View1_ModeChanging(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DetailsViewModeEventArgs)
إذا كان e.CancelingEdit = True AndAlso ErrorPanel.Visible = True إذن
ErrorPanel.Visible = خطأ
نهاية إذا
الموقف مشابه عندما
يستخدمEnd Sub
ObjectDataSource.لاحظ أنه نظرًا لتعيين خاصية ConflictDetection الخاصة بمصدر البيانات إلى CompareAllValues، سيبحث مصدر البيانات عن التحميل الزائد UpdateContact الذي يقبل القيمة الأولية لكل حقل في كائن جهة الاتصال.
يمكنك أيضًا استخدام الخاصية DataObjectTypeName وComparAllValues معًا. في هذه الحالة، يبحث ObjectDataSource عن التحميل الزائد UpdateContact الذي يقبل معلمتين فقط (كلاهما جهة الاتصال). المعلمة الأولى هي كائن جهة الاتصال الذي يخزن القيمة الجديدة، والمعلمة الثانية هي كائن جهة الاتصال الذي يخزن القيمة القديمة.