هل هذا خطأ في DataTable API؟يتم تخزين/تنفيذ التغييرات في "التسلسل الخاطئ"

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

  •  06-07-2019
  •  | 
  •  

سؤال

يحرر:أي تعليقات سواء كنت تعتقد أن هذا خطأ .NET أم لا سيكون موضع تقدير.

لدي خطأ تمكنت من تبسيطه إلى السيناريو التالي:

لدي DataTable حيث يجب الاحتفاظ بالمفاتيح الأساسية متتالية، على سبيل المثال:إذا قمت بإدراج صف بين صفوف أخرى، فيجب عليك أولاً زيادة معرف الصفوف التالية لتوفير مساحة، ثم قم بإدراج الصف.

وإذا قمت بحذف صف، فيجب عليك تقليل معرف أي صفوف تالية لملء الفجوة التي تركها الصف في الجدول.

حالة الاختبار التي تعمل بشكل صحيح

ابدأ بثلاثة صفوف في الجدول، بالمعرفات 1 و2 و3.

ثم قم بحذف المعرف = 2، وقم بتعيين المعرف = 2 حيث المعرف = 3 (لملء الفجوة)؛هذا يعمل بشكل صحيح.يحتوي dataTable.GetChanges() على الصف المحذوف، ثم الصف المعدل؛عند تشغيل dataAdapter.Update(table) يتم تنفيذه بشكل جيد.

حالة الاختبار التي لا تعمل

ومع ذلك، إذا بدأت بصفين (المعرفان 1 و2)، فقم بتعيين ID=3 حيث ID=2، وأدخل ID=2، ثم قم بتنفيذ (أو قبول) التغييرات.يجب أن تكون هذه الآن نفس حالة الاختبار الأول.

ثم تقوم بنفس الخطوات السابقة أياحذف ID=2 وقم بتعيين ID=2 حيث ID=3، ولكن الآن dataTable.GetChanges() بالترتيب الخاطئ.الصف الأول هو الصف المعدل، والصف الثاني هو الصف المحذوف.ثم إذا حاولت dataAdapter.Update(table) فسيؤدي ذلك إلى حدوث انتهاك للمفتاح الأساسي - فقد حاول تعديل صف إلى صف موجود بالفعل قبل حذفه.

الحل البديل

يمكنني التفكير في حل بديل للمشكلة، على سبيل المثال.فرضه بحيث يتم تنفيذ الصفوف المحذوفة أولاً، ثم تعديل الصفوف، ثم إضافة الصفوف.ولكن لماذا يحدث هذا؟هل هناك حل آخر؟

أعتقد أنني رأيت "مشكلة" مماثلة من قبل مع القواميس، وهي أنه إذا أضفت بعض العناصر، ثم حذفتها ثم أعدت إدراجها، فلن تكون بنفس التسلسل الذي أضفتها (عند تعداد القاموس).

فيما يلي اختباران لـ NUnit يوضحان المشكلة:

[Test]
public void GetChanges_Working()
{
    // Setup ID table with three rows, ID=1, ID=2, ID=3
    DataTable idTable = new DataTable();
    idTable.Columns.Add("ID", typeof(int));

    idTable.PrimaryKey = new DataColumn[] { idTable.Columns["ID"] };

    idTable.Rows.Add(1);
    idTable.Rows.Add(2);
    idTable.Rows.Add(3);

    idTable.AcceptChanges();

    // Delete ID=2, and move old ID=3 to ID=2
    idTable.Select("ID = 2")[0].Delete();
    idTable.Select("ID = 3")[0]["ID"] = 2;

    // Debug GetChanges
    foreach (DataRow row in idTable.GetChanges().Rows)
    {
        if (row.RowState == DataRowState.Deleted)
            Console.WriteLine("Deleted: {0}", row["ID", DataRowVersion.Original]);
        else
            Console.WriteLine("Modified: {0} = {1}", row["ID", DataRowVersion.Original], row["ID", DataRowVersion.Current]);
    }

    // Check GetChanges
    Assert.AreEqual(DataRowState.Deleted, idTable.GetChanges().Rows[0].RowState, "1st row in GetChanges should be deleted row");
    Assert.AreEqual(DataRowState.Modified, idTable.GetChanges().Rows[1].RowState, "2nd row in GetChanges should be modified row");
}

انتاج:

Deleted: 2
Modified: 3 = 2

1 passed, 0 failed, 0 skipped, took 4.27 seconds (NUnit 2.4).

الاختبار التالي:

[Test]
public void GetChanges_NotWorking()
{
    // Setup ID table with two rows, ID=1, ID=2
    DataTable idTable = new DataTable();
    idTable.Columns.Add("ID", typeof(int));

    idTable.PrimaryKey = new DataColumn[] { idTable.Columns["ID"] };

    idTable.Rows.Add(1);
    idTable.Rows.Add(2);

    idTable.AcceptChanges();

    // Move old ID=2 to ID=3, and add ID=2
    idTable.Select("ID = 2")[0]["ID"] = 3;
    idTable.Rows.Add(2);

    idTable.AcceptChanges();

    // Delete ID=2, and move old ID=3 to ID=2
    idTable.Select("ID = 2")[0].Delete();
    idTable.Select("ID = 3")[0]["ID"] = 2;

    // Debug GetChanges
    foreach (DataRow row in idTable.GetChanges().Rows)
    {
        if (row.RowState == DataRowState.Deleted)
            Console.WriteLine("Deleted: {0}", row["ID", DataRowVersion.Original]);
        else
            Console.WriteLine("Modified: {0} = {1}", row["ID", DataRowVersion.Original], row["ID", DataRowVersion.Current]);
    }

    // Check GetChanges
    Assert.AreEqual(DataRowState.Deleted, idTable.GetChanges().Rows[0].RowState, "1st row in GetChanges should be deleted row");
    Assert.AreEqual(DataRowState.Modified, idTable.GetChanges().Rows[1].RowState, "2nd row in GetChanges should be modified row");
}

انتاج:

Modified: 3 = 2
Deleted: 2
TestCase 'GetChanges_NotWorking'
failed: 
  1st row in GetChanges should be deleted row
  Expected: Deleted
  But was:  Modified
هل كانت مفيدة؟

المحلول

هذا ليس خطأ، النقطة المهمة هي أنك تستخدم معرفات بطريقة غير قياسية (جدًا).إجابتان:

1) استخدم DataTable.GetChanges(DataRowState.Modified) لمعالجة تحديثاتك بالترتيب (أعتقد أنه سيتم حذفها أو تعديلها أو إدراجها).وهذا ما يجب عليك فعله مع العلاقات الرئيسية/التفصيلية أيضًا (قبل .net 3.0)

2) أعد التفكير في تصميمك، بشكل عام، يجب أن تكون بطاقات التعريف غير قابلة للتغيير وتسمح بوجود فجوات وما إلى ذلك.وهذا سيجعل جميع عمليات قاعدة البيانات الخاصة بك أكثر موثوقية وأسهل بكثير.يمكنك استخدام عمود آخر للاحتفاظ بالترقيم التسلسلي لتقديمه إلى المستخدم.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top