2009-05-06 23 views
5

Đây là thiết kế được đề xuất (rất đơn giản để minh họa không gian vấn đề) cho ứng dụng giao diện điều khiển C#. Các kết nối cơ sở dữ liệu thực hiện IDisposable và giải pháp này không cho phép các đối tượng kết nối cơ sở dữ liệu using. Ai đó có thể đề xuất cấu trúc chính xác hơn cho ứng dụng bảng điều khiển? Đây là một vấn đề tôi cần phải giải quyết thường xuyên.Làm cách nào để cấu trúc ứng dụng giao diện điều khiển C# để sử dụng hiệu quả tài nguyên cơ sở dữ liệu IDisposable?

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 
    } 
} 

Edit:

Một số người không thể tìm ra lý do tại sao tôi muốn họ như biến thành viên. Đây là trường hợp sử dụng của tôi (một chút psuedocoded) của những gì sẽ đi trong doDatabaseWork:

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

Xem cách tôi muốn giữ các kết nối này mở trong vòng đời này?

+0

RE: Chỉnh sửa. Tuy nhiên ... không có –

Trả lời

2

Tôi nghĩ giải pháp tốt nhất là trích xuất logic chính từ lớp Chương trình. Lớp chương trình là một loại khởi động cho công việc chính. Và cung cấp trình bao bọc cho SqlConnections không phải là một ý tưởng hay, vì chúng được quản lý tài nguyên rồi, gói chúng là thừa. Vì vậy, giải pháp của tôi trông giống như sau:

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 
    } 
} 
+0

Kết nối được lấy từ hồ bơi kết nối. Do đó nếu bạn không mở và đóng chúng 1000 lần một giây, nó sẽ không ảnh hưởng đến hiệu suất của chương trình của bạn. Nhưng nếu bạn cần phải mở và đóng kết nối rất thường xuyên, sau đó bạn nên sử dụng bộ nhớ đệm của dữ liệu bên trong chương trình của bạn. Nhưng điều này liên quan đến tối ưu hóa, và bạn nên cẩn thận hồ sơ chương trình của bạn để tối ưu hóa nó. Hãy nhớ những gì Donald Knuth nói về tối ưu hóa: "Chúng ta nên quên đi hiệu quả nhỏ, nói khoảng 97% thời gian: tối ưu hóa sớm là gốc rễ của mọi điều ác". –

+0

Đủ công bằng, nhưng chiến lược đầu tiên của tôi là chỉ mở và đóng các kết nối db khi tôi cần chúng. Nó đã chậm lại trong quá trình thu thập dữ liệu trong suốt thời gian của kịch bản. Tôi đã không hồ sơ, nhưng thậm chí chỉ cần nhóm các ghi vào các nhóm của một 1000 cho mỗi kết nối thực hiện quản lý. – danieltalsky

+0

Thành thật mà nói, không ai nâng cao chiến lược của bạn, nhưng cho đến nay nó là gần nhất để trả lời câu hỏi của tôi. – danieltalsky

6

Cách viết một lớp thực hiện IDisposable.

Bên trong trình tạo lớp, bạn có thể khởi tạo kết nối DB của mình.

Sau đó, bên trong phương thức IDisposable.Dispose của bạn, bạn viết mã rách xuống để đóng kết nối DB của mình.

Đây là một mẫu mã để chứng minh những gì tôi muốn nói:

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

Và sau đó, từ bên trong phương pháp chính của buổi học Chương trình của bạn:

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

Phải, nhưng tôi có hai kết nối cơ sở dữ liệu và họ cần để có thể lấy tài nguyên từ một, chuyển đổi chúng và ghi vào một tài nguyên khác. Tôi không muốn phải kết nối lại cho mỗi lần đọc và viết. Tôi chỉ muốn có một xử lý để cả hai mở, và sau đó có thể thực hiện các hoạt động trên mỗi khi tôi cần. Tôi có làm sourceWrapper.DoWork (destinationWrapper) không? – danieltalsky

+0

Thử mở 2 hoặc nhiều độc giả trên đối tượng kết nối đó và xem tại sao điều này không hoạt động tốt như vậy –

+0

Tôi vừa thay đổi mẫu mã của mình rõ ràng hơn với 2 đối tượng Kết nối Bên trong phương thức DoWork, bạn đã có quyền truy cập vào cả hai SqlConnections, bạn có thể làm bất cứ điều gì bạn cần, mà không cần phải kết nối lại cho mỗi đọc và viết. Về cơ bản, bạn đang trừu tượng hóa logic DB thành phương thức DBWrapper.DoWork() và tránh phương thức Program.Main của bạn. –

2

câu trả lời của Scott là một cách để làm điều đó . Bạn cũng có thể cân nhắc sử dụng try {} cuối cùng thay thế?

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

Tại sao không chỉ sử dụng từ khóa đang sử dụng cho sourceConnection và destinationConnection? –

+0

Điều đó có hiệu quả không? Trả lời và hiển thị một mẫu mã hợp lệ, Brian? – danieltalsky

2

Cá nhân, tôi nghĩ bạn đang suy nghĩ về điều này và các mẫu mã trong chuỗi này quá phức tạp. Tôi không có ý tưởng tại sao mọi người đang thực hiện IDisposable trên lớp chương trình của họ, hoặc kể từ khi nó được xử lý khi nó thoát.

Tôi không thể nghĩ ra một lý do nào để không sử dụng hoặc lý do bạn không thể sử dụng câu lệnh using() {}.

Bạn muốn mở một kết nối và giữ nó? Tại sao? Tất cả các kết nối thực sự là đằng sau hậu trường trong kết nối .net kết nối, vì vậy new'ing Kết nối đối tượng không phải là một việc lớn. Chỉ cần mở và đóng khi bạn cần chúng và kết nối tổng hợp xử lý tất cả những gì đằng sau hậu trường.

Tôi đã chỉnh sửa ví dụ của mình để bọc nó trong một lớp để bạn cũng có thể đóng gói của mình.

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

} 
+0

Tôi muốn có thể có các phương thức trợ giúp riêng biệt thực sự thực hiện việc đọc và ghi để tôi có thể có logic dịch dữ liệu từ một sang phương thức khác theo phương thức riêng của nó. Nếu tôi không lưu trữ dữ liệu như một thành viên, thì tôi không có quyền truy cập vào các kết nối khi tôi cần chúng. – danieltalsky

+0

Tôi đã thêm bản chỉnh sửa để cho biết lý do tôi đấu tranh với mã đó. – danieltalsky

0

Hmm, tôi thấy không có ai đề cập đến việc đó theo cách này. Bạn không cần phải có các biến được sử dụng trong số using được khai báo cục bộ.


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 
    } 
} 
Các vấn đề liên quan