5

これは、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);
}

このループの存続期間中、これらの接続を開いたままにしておく方法がわかりますか?

4

5 に答える 5

6

IDisposable を実装するクラスを作成するのはどうですか。

クラス コンストラクター内で、DB 接続をインスタンス化できます。

次に、IDisposable.Dispose メソッド内で、DB 接続を閉じるための分解コードを記述します。

私が何を意味するかを示すコードサンプルを次に示します。

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();
        }
    }
}

次に、Program クラスのメイン メソッド内から:

class Program
{
    static void Main(string[] args)
    {
        using (DBWrapper wrapper = new DBWrapper())
        {
            wrapper.DoWork();
        }
    }
}
于 2009-05-06T03:23:58.800 に答える
2

個人的には、あなたはこれを考えすぎていると思います。このスレッドのコードサンプルは非常に複雑です。IDisposableが終了時に破棄されるため、なぜ人々がプログラムクラスにIDisposableを実装しているのかわかりません。

使用しない理由や、using(){}ステートメントを使用できない理由は1つも考えられません。

接続を開いて保持しますか?なんで?実際の接続はすべて.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();
            }
        }
    }

}
于 2009-05-06T04:21:35.980 に答える
2

スコットの答えはそれを行う一つの方法です。代わりに、最終的にtry {}を使用することも検討できますか?

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();
    }
}
于 2009-05-06T03:25:42.027 に答える
2

Program クラスから主なロジックを抽出するのが最善の解決策だと思います。Program クラスは、主要な作業のスターターのようなものです。また、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
    }
}
于 2009-05-06T04:42:38.753 に答える
0

うーん、誰もこのようにすることについて言及していないようです。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
    }
}
于 2009-05-07T21:51:01.720 に答える