هل يمكنك تضمين تغييرات LinQ-To-SQL وتحديثات ADO.NET DataSet Adapter في معاملة واحدة؟

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

سؤال

فيما يلي التقنيات ذات الصلة التي أعملها مع:

  • Devart's Dot Connect for Oracle (لتسهيل LinQ-to-SQL ل Oracle).
  • مكتوبة بقوة بيانات ADO.NET.
  • قاعدة بيانات أوراكل.

إليك التحدي:

  • يقدم رمز Legacy الخاص بي تحديثات قاعدة البيانات مع مجموعات البيانات ADO.NET ومحولات الجدول.
  • أود أن أبدأ في تحويل هذا الرمز إلى LinQ-To-SQL، لكنني أرغب في القيام بذلك مجزأة لتقليل تخليص شفرة المخاطر والمخاطر.

إليك إثبات مخطط المفهوم الخاص بي:

الجدول الأم

  • Parent.id.
  • اسم الوالدين

طاولة الطفل

  • child.id.
  • childent.parentid.
  • اسم الطفل

إليك دليلي على كتلة رمز المفهوم:

using System;
using System.Data.Common;
using DevArtTry1.DataSet1TableAdapters;

namespace DevArtTry1
{
    class Program
    {
        static void Main(string[] args)
        {
            using (DataContext1 dc = new DataContext1())
            {
                dc.Connection.Open();
                using (DbTransaction transaction = dc.Connection.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
                {
                    dc.Transaction = transaction;

                    Parent parent = new Parent();
                    parent.Id = 1;
                    parent.Name = "Parent 1";
                    dc.Parents.InsertOnSubmit(parent);
                    dc.SubmitChanges(); // By virtue of the Parent.Id -> Child.ParentId (M:N) foreign key, this statement will impose a write lock on the child table.

                    DataSet1.CHILDDataTable dt = new DataSet1.CHILDDataTable();
                    DataSet1.CHILDRow row = dt.NewCHILDRow();
                    row.ID = 1;
                    row.PARENTID = 1;
                    row.NAME = "Child 1";
                    dt.AddCHILDRow(row);

                    CHILDTableAdapter cta = new CHILDTableAdapter();
                     // cta.Transaction = transaction;  Not allowed because you can't convert source type 'System.Data.Common.DbTransaction to target type 'System.Data.OracleClient.OracleTransaction.
                    cta.Update(dt); // The thread will encounter a deadlock here, waiting for a write lock on the Child table.
                    transaction.Commit();
                }
            }

            Console.WriteLine("Successfully inserted parent and child rows.");
            Console.ReadLine();
        }
    }
}

  • نظرا لأن التعليقات أعلاه تشير إلى توقف الخيط بشكل غير مسمى على مكالمة تحديث محول بيانات الطفل لأنها ستنتظر إلى أجل غير مسمى للحصول على قفل الكتابة على طاولة الطفل. [لاحظ العلاقة الرئيسية الأجنبية: Parent.id -> childer.parentid (m: n)

إليك سؤالي:

  • أريد أن ألتف كتلة الكود بأكملها في معاملة.
  • هل يمكنني فعل هذا؟ معتبرا أن:
    • أريد أن أرتكب تحديثا على الجدول الأصل مع LinQ-To-SQL طريقة submitchanges...
    • وأريد ارتكاب تحديث على طاولة الطفل باستخدام مجموعة بيانات ADO.NET محول الجدول.

هنا اثنين من الحواشي المهمة:

  1. هذه الأشياء كلها ويعمل إلى الوراء. وهذا هو، إذا أردت تقديم تغييرات على الجدول الأصل مع محول البيانات والتغييرات في جدول الطفل مع LinQ-To-SQL ... ذلك سوف تعمل.
  2. حاولت إرفاق المعاملة بشكل صريح إلى DataAdapter، لكن المحول البرمجي لن يسمح له لأنه نوع مختلف من المعاملة.

                    CHILDTableAdapter cta = new CHILDTableAdapter();
                cta.Transaction = transaction; // Not allowed because you can't convert source type 'System.Data.Common.DbTransaction' to target type 'System.Data.OracleClient.OracleTransaction'.
                cta.Update(dt);
                transaction.Commit();
    
هل كانت مفيدة؟

المحلول

لا أعرف أي شيء عن معاملات Oracle ... ولكن على جانب Dotnet، يجب أن تكون على ما يرام للتحكم في المعاملة بنفسك. تأكد من أن كلا التكنولوجيات تستخدم نفس مثيل الاتصال.

عندما نتحكم في المعاملات من خلال الاتصال بدلا من خلال Orm، نستخدم نطاق المعاملات: http://msdn.microsoft.com/en-us/library/ms172152.aspx.

نصائح أخرى

كان لدي نفس المشكلة، واجهت هذه الأخطاء:

  • انتهاك قيود النزاهة (ORA-02291)
  • "لا يمكن إدراج كيان مع نفس المفتاح إذا لم يتم إنشاء مفتاح قاعدة البيانات"

كانت المشكلة هي أن عمود هوية كائن الطفل لم يتم تعيينه بشكل صحيح. إذا لم يفترض DotConnect LinQ مفتاح الهوية، فيمكن أن تضع خصائص الكائنات مخصصة، مما يؤدي إلى تحديثات غير متسلسلة، مما يؤدي إلى انتهاكات النزاهة.

إليك الإصلاح:

  • يحتاج LINQ إلى معرفة أن المفتاح الأساسي للطفل هو مفتاح كيان ولدت تلقائيا.
  • في Oracle، قم بإعداد مفتاح زيادة تلقائية لكائن الطفل.
  • أولا إنشاء تسلسل:

      DROP SEQUENCE MyChild_SEQ;
      CREATE SEQUENCE MyChild_SEQ
          MINVALUE 1
          MAXVALUE 999999999999999999999999999
          START WITH 1
          INCREMENT BY 1
          CACHE 20;
    
  • التالي إنشاء الزيجر OninSert:

    CREATE OR REPLACE TRIGGER MyChild_AUTOINC 
    BEFORE INSERT
    ON MyChildObject
    FOR EACH ROW
    BEGIN
      SELECT MyChild_SEQ.nextval
      INTO :NEW.MyChild_ID
      FROM dual;
    END MyChild_AUTOINC ; 
    ALTER TRIGGER MyChild_AUTOINC ENABLE
    
  • قم بتعديل نموذج التخزين لدمج المفتاح الأساسي الذي تم إنشاؤه تلقائيا:

    • في EntityDeveloper ل DotConnect، افتح طراز تخزين LinQ الخاص بك (ملف .lqml).
    • قم بتعيين مفتاح كيان كائن الطفل على "القيمة المولدة تلقائيا"، والزدامن التلقائي إلى "Oninsert".
    • احفظ طراز التخزين، وفي Visual Studio، نظف وإعادة بناء الحل.
    • قم بإزالة أي رمز يضع بشكل صريح المفتاح الأساسي للطفل.
      • ستعترف LinQ ضمنيا بهذا مثل زيادة التلقائي واسترداد معرف المنشأة التي تم إنشاؤها.
  • في التعليمات البرمجية، بعد إنشاء كائن الطفل، إرفاقه إلى الوالد، على النحو التالي:

    ChildType newChild = new ChildType();
    DataContext.InsertOnSubmit(newChild);
    Parent.Child = newChild;
    

فيما يلي موارد أخرى:

هتافات!

استخدام فئة المعاملات.

احذر أنه إذا كنت تستخدم قواعد بيانات مختلفة (أو أنها تقيم على الخوادم المميزة)، فأنت بحاجة إلى التحقق من تكوين DTC الخاص بك.

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