كيف أقوم ببناء تطبيق وحدة تحكم C# لاستخدام موارد قاعدة بيانات IDisposable بكفاءة؟

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

سؤال

هذا هو التصميم المقترح (المبسط جدًا لتوضيح مساحة المشكلة) لتطبيق وحدة التحكم C#.تقوم اتصالات قاعدة البيانات بتنفيذ IDisposable، وهذا الحل لا يسمح بذلك using كائنات اتصال قاعدة البيانات.هل يمكن لأي شخص أن يقترح بنية أكثر صحة لتطبيق وحدة التحكم؟هذه مشكلة أحتاج إلى حلها كثيرًا.

class Program 
{
    SQLiteConnection sourceConnection;
    SQLiteConnection destinationConnection;

    static void Main(string[] args)
    {
        Program shell = new Program();

        // get connection strings from command line arguments
        string sourceConnectionString = shell.getConnectionString(args);
        string destinationConnectionString = shell.getConnectionString(args);

        // call non-static methods that use
        shell.setUpConnections(sourceConnectionString, destinationConnectionString);

        shell.doDatabaseWork();
    }

    private void setUpConnections(string sourceConnectionString, string destinationConnectionString)
    {
        sourceConnection = new SQLiteConnection(sourceConnectionString);
        destinationConnection = new SQLiteConnection(destinationConnectionString);
    }

    private void doDatabaseWork()
    {
        // use the connections here
    }
}

يحرر:

لا يستطيع بعض الأشخاص معرفة سبب رغبتي في جعلهم متغيرات للأعضاء.إليك حالة الاستخدام الخاصة بي (قليلاً من التشفير) لما يمكن أن يحدث في doDatabaseWork:

foreach (Row sourceRow in DBResultSet)
{
  string sourceXml = sourceRow.Columns["MyColumnName"].Value;
  string destinationXML = transformUsingXSLT(sourceXml);
  writeToDestination(destinationXml);
}

هل ترى كيف أرغب في إبقاء هذه الاتصالات مفتوحة طوال مدة هذه الحلقة؟

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

المحلول

أعتقد أن الحل الأفضل هو استخراج المنطق الرئيسي من فئة البرنامج.تعد فئة البرنامج بمثابة بداية للعمل الأساسي.وتوفير أغلفة لـ SqlConnections ليس فكرة جيدة بالفعل، لأنها موارد مُدارة بالفعل، وتغليفها زائدة عن الحاجة.وبالتالي يبدو الحل الخاص بي كما يلي:

class ProgramCore : IDisposable
{
    internal ProgramCore(string sourceConnectionString, string destinationConnectionString)
    {
        setUpConnections(sourceConnectionString, destinationConnectionString);
    }

    internal void Execute()
    {
        // do whatever you want
        doDatabaseWork();
        // do whatever you want
    }

    public void Dispose()
    {
        if (_sourceConnection != null)
            _sourceConnection.Dispose();
        if (_destinationConnection != null)
            _destinationConnection.Dispose();
    }

    private void setUpConnections(string sourceConnectionString, string destinationConnectionString)
    {
        _sourceConnection = new SQLiteConnection(sourceConnectionString);
        _destinationConnection = new SQLiteConnection(destinationConnectionString);
    }

    private void doDatabaseWork()
    {
        // use the connections here
    }

    private SQLiteConnection _sourceConnection;
    private SQLiteConnection _destinationConnection;
}

class Program
{
    static void Main(string[] args)
    {
        // get connection strings from command line arguments
        string sourceConnectionString = GetConnectionString(args);
        string destinationConnectionString = GetConnectionString(args);

        using (ProgramCore core = new ProgramCore(sourceConnectionString, destinationConnectionString))
        {
            core.Execute();
        }
    }

    static string GetConnectionString(string[] args)
    {
        // provide parsing here
    }
}

نصائح أخرى

ماذا عن كتابة فصل دراسي يقوم بتطبيق IDisposable.

داخل مُنشئ الفصل الدراسي الخاص بك، يمكنك إنشاء مثيل لاتصالات قاعدة البيانات الخاصة بك.

ثم داخل طريقة IDisposable.Dispose الخاصة بك، تكتب التعليمات البرمجية الممزقة لإغلاق اتصالات قاعدة البيانات الخاصة بك.

فيما يلي نموذج التعليمات البرمجية لتوضيح ما أعنيه:

public class DBWrapper : IDisposable
{
    public SqlConnection Connection1 { get; set; }
    public SqlConnection Connection2 { get; set; }

    public DBWrapper()
    {
        Connection1 = new SqlConnection();
        Connection1.Open();
        Connection2 = new SqlConnection();
        Connection2.Open();
    }
    public void DoWork()
    {
        // Make your DB Calls here
    }

    public void Dispose()
    {
        if (Connection1 != null)
        {
            Connection1.Dispose();
        }
        if (Connection2 != null)
        {
            Connection2.Dispose();
        }
    }
}

وبعد ذلك، من داخل طريقتك الرئيسية لفئة البرنامج الخاصة بك:

class Program
{
    static void Main(string[] args)
    {
        using (DBWrapper wrapper = new DBWrapper())
        {
            wrapper.DoWork();
        }
    }
}

إجابة سكوت هي إحدى الطرق للقيام بذلك.هل يمكنك أيضًا التفكير في استخدام المحاولة{} أخيرًا بدلاً من ذلك؟

static void Main(string[] args)
{
    Program shell = new Program();

    // get connection strings from command line arguments
    string sourceConnectionString = shell.getConnectionString(args);
    string destinationConnectionString = shell.getConnectionString(args);

    // call non-static methods that use
    shell.setUpConnections(sourceConnectionString, destinationConnectionString);
    try
    {
      shell.doDatabaseWork();
    }
    finally
    {
      if(sourceConnection != null)
        sourceConnection.Dispose();
      if(destinationConnection != null)
        destinationConnection.Dispose();
    }
}

شخصيًا، أعتقد أنك قد بالغت في التفكير في هذا الأمر وأن نماذج التعليمات البرمجية الموجودة في هذا الموضوع معقدة للغاية.ليس لدي أي فكرة عن سبب قيام الأشخاص بتنفيذ IDisposable في فئة البرنامج الخاصة بهم أيضًا نظرًا لأنه يتم التخلص منه عند الخروج.

لا أستطيع التفكير في سبب واحد لعدم الاستخدام أو لماذا لا يمكنك استخدام عبارة use(){}.

هل تريد فتح اتصال والاحتفاظ به؟لماذا؟جميع الاتصالات الحقيقية تكون خلف الكواليس في تجمع اتصالات .net، لذا فإن كائنات الاتصال الجديدة لا تمثل مشكلة كبيرة.ما عليك سوى فتحها وإغلاقها حسب حاجتك إليها، وسيتعامل تجميع الاتصالات مع كل ما يحدث خلف الكواليس.

لقد قمت بتحرير المثال الخاص بي لتغليفه في فصل دراسي حتى تتمكن من الحصول على التغليف الخاص بك أيضًا.

class Program 
{
    static void Main(string[] args)
    {
        DBWorker worker = new DBWorker();
        worker.DoDatabaseWork();
    }
}

public class DBWorker 
{

    private void DoDatabaseWork()
    {
        using (SQLiteConnection sourceDB = new SQLiteConnection( GetConnectionString() ))
        {
            sourceDB.Open();
            using (SQLiteConnection destDB = new SQLiteConnection( GetConnectionString() ))
            {
                destDB.Open();
            }
        }
    }

}

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


class Program 
{
    SQLiteConnection sourceConnection;
    SQLiteConnection destinationConnection;

    static void Main(string[] args)
    {
        Program shell = new Program();

        // get connection strings from command line arguments
        string sourceConnectionString = shell.getConnectionString(args);
        string destinationConnectionString = shell.getConnectionString(args);

        using (sourceConnection = new SQLiteConnection(sourceConnectionString))
        using (destinationConnection = new SQLiteConnection(destinationConnectionString))
        {
            shell.doDatabaseWork();
        }
    }

    private void doDatabaseWork()
    {
        // use the connections here
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top