簡體   English   中英

如何構建C#控制台應用程序以有效使用IDisposable數據庫資源?

[英]How do I structure a C# console application to efficiently use IDisposable database resources?

這是我為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);
}

看看我想如何在這個循環的生命周期中保持這些連接打開?

編寫一個實現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();
        }
    }
}

然后,從您的Program類的main方法中:

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

斯科特的答案是一種方法。 您還可以考慮最后使用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();
    }
}

就個人而言,我認為你已經在考慮這個問題了,這個帖子中的代碼示例過於復雜了。 我不知道為什么人們在他們的Program類上實現IDisposable,因為它在退出時被處理掉了。

我想不出一個不使用的原因或為什么你不能使用using(){}語句。

你想打開一個連接並持有它嗎? 為什么? 所有真正的連接都在.net連接池的幕后,所以新的Connection對象並不是什么大問題。 只需在需要時打開和關閉,連接池就可以處理幕后的所有操作。

我編輯了我的例子將它包裝在一個類中,這樣你也可以進行封裝。

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

}

我認為最好的解決方案是從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
    }
}

嗯,我看到沒有人提到這樣做。 您不必擁有在本地聲明的使用中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 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM