idisposable 데이터베이스 리소스를 효율적으로 사용하기 위해 C# 콘솔 애플리케이션을 구조하려면 어떻게해야합니까?

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에서 어떤 일이 될지에 대한 나의 유스 케이스 (약간의 psuedocoded)입니다.

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

이 루프의 수명을 위해이 연결을 어떻게 열어두고 싶은지 보시겠습니까?

도움이 되었습니까?

해결책

최선의 해결책은 프로그램 클래스에서 주요 논리를 추출하는 것입니다. 프로그램 클래스는 기본 작업을위한 일종의 스타터입니다. 그리고 SQLConnection을위한 포장지를 제공하는 것은 실제로 관리 자원이기 때문에이를 포장하기 때문에 중복됩니다. 따라서 내 솔루션은 다음과 같습니다.

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을 구현하는 수업을 작성하는 것은 어떻습니까?

클래스 생성자 내에서 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();
        }
    }
}

그런 다음 프로그램 클래스의 주요 방법 내에서 :

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

개인적으로, 나는 당신이 이것을 지나치게 생각하고 있으며이 스레드의 코드 샘플은 지나치게 복잡한 IMHO라고 생각합니다. 사람들이 종료 될 때 배치 된 이후로 사람들이 프로그램 클래스에서 Idisposable을 구현하는 이유를 모르겠습니다.

사용하지 않는 한 가지 이유 또는 사용 () {} 문을 사용할 수없는 이유를 생각할 수 없습니다.

연결을 열고 고정하고 싶습니까? 왜요? 모든 실제 연결은 .NET Connection Pooling의 무대 뒤에 있으므로 새로운 연결 객체는 큰 문제가 아닙니다. 필요한대로 열리고 가까이 다가 가고 연결 풀링은 무대 뒤에서 모든 것을 처리합니다.

내 예제를 편집하여 수업에 랩핑하여 캡슐화를 할 수 있습니다.

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