سؤال

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

هل كانت مفيدة؟

المحلول

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

والميزة الرئيسية في تمرير الاتصالات <م> تستخدم أن يكون بحيث يمكن تمرير الصفقة حولها؛ ومع ذلك، TransactionScope هو أبسط طريقة لتقاسم صفقة بين الأساليب.

ومنذ الطبقات هي محددة للتنفيذ، كنت أكتب كل لفتحه من الصفقة التي نشأ فيها. خلاف ذلك، يمكنك استخدام الأساليب مصنع ado.net لخلق النوع المناسب من ملف التكوين (اسم مقدم).

نصائح أخرى

أنا شخصياً أحب تخزين مجموعة من اتصالاتي ومعاملاتي المفتوحة الحالية أعلى الملف موضوع التخزين المحلي باستخدام SetData وGetData.أحدد فئة تدير اتصالاتي بقاعدة البيانات وأسمح لها باستخدام نمط التخلص.وهذا يوفر علي الحاجة إلى تمرير الاتصالات والمعاملات، وهو أمر أعتقد أنه يربك الكود ويعقده.

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

لذلك انتهى بي الأمر بالحصول على شيء على هذا المنوال (لم يتم اختباره على الإطلاق):

class DatabaseContext : IDisposable {

    List<DatabaseContext> currentContexts;
    SqlConnection connection;
    bool first = false; 

    DatabaseContext (List<DatabaseContext> contexts)
    {
        currentContexts = contexts;
        if (contexts.Count == 0)
        {
            connection = new SqlConnection(); // fill in info 
            connection.Open();
            first = true;
        }
        else
        {
            connection = contexts.First().connection;
        }

        contexts.Add(this);
    }

   static List<DatabaseContext> DatabaseContexts {
        get
        {
            var contexts = CallContext.GetData("contexts") as List<DatabaseContext>;
            if (contexts == null)
            {
                contexts = new List<DatabaseContext>();
                CallContext.SetData("contexts", contexts);
            }
            return contexts;
        }
    }

    public static DatabaseContext GetOpenConnection() 
    {
        return new DatabaseContext(DatabaseContexts);
    }


    public SqlCommand CreateCommand(string sql)
    {
        var cmd = new SqlCommand(sql);
        cmd.Connection = connection;
        return cmd;
    }

    public void Dispose()
    {
        if (first)
        {
            connection.Close();
        }
        currentContexts.Remove(this);
    }
}



void Test()
{
    // connection is opened here
    using (var ctx = DatabaseContext.GetOpenConnection())
    {
        using (var cmd = ctx.CreateCommand("select 1"))
        {
            cmd.ExecuteNonQuery(); 
        }

        Test2(); 
    }
    // closed after dispose
}

void Test2()
{
    // reuse existing connection 
    using (var ctx = DatabaseContext.GetOpenConnection())
    {
        using (var cmd = ctx.CreateCommand("select 2"))
        {
            cmd.ExecuteNonQuery();
        }
    }
    // leaves connection open
}

لأغراض الاختبار الآلي، انها عادة ما تكون أسهل لتمريرها في. وهذا ما يسمى حقن التبعية .

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

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

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

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

كن حذرا لقابلية عدم تمرير اتصال معينة إذا كان سيتم استدار الحل لقواعد البيانات الأخرى (بمعنى لا تنزعج تمرير SqlConnection ذلك كنت تخطط للعمل مع قواعد البيانات الأخرى)

وإعداد اتصال يحتمل أن تكون مكلفة، وربما يضيف ذهابا وإيابا. هكذا، مرة أخرى، من المحتمل، وتصميم أفضل هو لتمرير كائن الاتصال.

وأقول يحتمل، لأنه إذا كنت التطبيق مايكروسوفت ADO، وربما كنت تستخدم تجمع اتصال ....

وأود أن أقترح عليك أن تميز بين كائن الاتصال وحالته (مفتوحة، مغلقة).

هل يمكن أن يكون أسلوب واحد (أو الممتلكات) الذي يقرأ سلسلة الاتصال من الملف web.config. باستخدام نفس الإصدار من سلسلة الاتصال في كل مرة يضمن لك سوف تستفيد من تجمع الاتصال.

واستدعاء هذا الأسلوب عندما تحتاج إلى فتح اتصال. في آخر لحظة، بعد إعداد كافة الخصائص SqlCommand، فتح الاتصال، واستخدامها، ومن ثم إغلاقه. في C #، يمكنك استخدام العبارة باستخدام للتأكد من إغلاق الاتصال. إذا لم يكن كذلك، يجب التأكد من إغلاق الاتصال في كتلة أخيرا.

وأود أن استخدام الملف web.config

<configuration>
    <connectionStrings>
        <add name="conn1" providerName="System.Data.SqlClient" connectionString="string here" />
        <add name="conn2" providerName="System.Data.SqlClient" connectionString="string here" />
    </connectionStrings>
</configuration>

وبعد ذلك يمكنك الرجوع إليها من أي مكان في التطبيق

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