2012-06-27 43 views
7

Tôi đang làm việc với đối tượng DAL được viết trong bố cục tương tự như mã sau. Tôi đã đơn giản hóa rất nhiều mã mã chỉ để hiển thị thiết lập.Bạn có nên sử dụng lại các đối tượng SqlConnection, SqlDataAdapter và SqlCommand không?

public class UserDatabase : IDisposable 
{ 
    private SqlDataAdapter UserDbAdapter; 
    private SqlCommand UserSelectCommand; 
    private SqlCommand UserInsertCommand; 
    private SqlCommand UserUpdateCommand; 
    private SqlCommand UserDeleteCommand; 

    private System.Data.SqlClient.SqlConnection SQLConnection; 

    public UserDatabase() 
    { 
     this.SQLConnection = new System.Data.SqlClient.SqlConnection(ConnectionString); 
     this.UserDbAdapter= new SqlDataAdapter(); 
     this.UserDbAdapter.DeleteCommand = this.UserDeleteCommand; 
     this.UserDbAdapter.InsertCommand = this.UserInsertCommand; 
     this.UserDbAdapter.SelectCommand = this.UserSelectCommand; 
     this.UserDbAdapter.UpdateCommand = this.UserUpdateCommand; 
    } 

    private bool FillUsers(DataSet UserDataSet, out int numberOfRecords) 
    { 
     bool success = true; 

     numberOfRecords = 0; 
     string errorMsg = null; 

     this.UserDbAdapter.SelectCommand = this.GetUsersSelectCommand(); 

     numberOfRecords = UserDbAdapter.Fill(UserDataSet, UsersTableName); 

     return success; 
    } 

    private SqlCommand GetUserSelectCommand() 
    { 
     if (this.UserSelectCommand==null) 
      this.UserSelectCommand= new System.Data.SqlClient.SqlCommand(); 
     this.UserSelectCommand.CommandText = "dbo.Users_Select"; 
     this.UserSelectCommand.CommandType = System.Data.CommandType.StoredProcedure; 
     this.UserSelectCommand.Connection = this.SQLConnection; 
     this.UserSelectCommand.Parameters.Clear(); 
     this.UserSelectCommand.Parameters.AddRange(new System.Data.SqlClient.SqlParameter[] { 
     new System.Data.SqlClient.SqlParameter("@RETURN_VALUE", System.Data.SqlDbType.Variant, 0, System.Data.ParameterDirection.ReturnValue, false, ((byte)(0)), ((byte)(0)), "", System.Data.DataRowVersion.Current, null)}); 

     return UserSelectCommand; 
    } 

Có nhiều hàm Fill type khác được viết giống như cách sử dụng lại đối tượng Connection, SqlCommands và SqlDataAdapter. SqlDataAdapter quản lý việc mở và đóng SqlConnection bên trong.

Vì vậy, câu hỏi của tôi là đa phần. Thiết kế này có tệ không? Nếu vậy, tại sao?

Nếu nó là xấu, nó nên được thay đổi để giữ mọi thứ trong một phạm vi địa phương hơn như sau:

public bool FillUsers(DataSet UserDataSet) 
    { 
     using (SqlConnection conn = new SqlConnection(ConnectionString)) 
     { 
      using (SqlCommand command = GetUsersSelectCommand()) 
      { 
       using (SqlDataAdapter adapter = new SqlDataAdapter(command, conn)) 
       { 
        adapter.Fill(UserDataSet, UsersTableName); 
       } 
      } 
     } 
    } 

này sẽ phải được thực hiện đối với tất cả các chức năng mà dường như tạo, xử lý, và sau đó làm lại sẽ tồi tệ hơn việc giữ các vật phẩm xung quanh. Tuy nhiên, điều này có vẻ là thiết lập tôi thấy ở mọi nơi trực tuyến.

+0

Bạn có đo lường vấn đề hiệu suất như vậy mà bạn cảm thấy cần phải tối ưu hóa không? Kết nối cơ sở dữ liệu được gộp theo thiết kế. Không cần phải "repool" trên đầu trang. – spender

+0

Câu hỏi tương tự tôi đã hỏi một vài năm trước: http://stackoverflow.com/questions/226127/multiple-single-instance-of-linq-to-sql-datacontext – spender

+0

Không có vấn đề về hiệu suất nào được liên kết lại. Tôi đang bắt đầu một dự án mới và cần một đối tượng truy cập dữ liệu và tò mò nếu điều này là "đúng" hoặc nếu có một cách tốt hơn. – Equixor

Trả lời

8

Không, không có gì sai với điều đó. Bạn nên vứt bỏ các đối tượng thực hiện IDisposable ngay khi bạn hoàn thành chúng.

Cho một SqlConnection, khi bạn vứt bỏ kết nối, kết nối cơ bản sẽ chỉ được trả về hồ bơi. Nó không nhất thiết phải "đóng cửa" như bạn nghĩ. Tốt nhất là để hồ bơi kết nối thực hiện công việc của mình. Here là một liên kết trên MSDN để kết nối ADO.NET. Cố gắng để làm cho nó làm những điều nó không được thiết kế cho (một số người gọi đây là tối ưu hóa, đáng ngạc nhiên) thường là một chuyến đi xuống hố thỏ.

Ngoài ra, hãy đảm bảo bạn đã thực sự đo lường và quan sát thấy sự cố trước khi cố gắng tối ưu hóa vấn đề. (và tôi không ngụ ý điều này một cách khắc nghiệt, chỉ để giúp bạn tiết kiệm thời gian).

+0

Mã trên cùng không loại bỏ bất kỳ đối tượng nào cho đến khi đối tượng UserDatabase được xử lý. Vì vậy, có vẻ như tái sử dụng chúng sẽ đi ngược lại thực hành thiết kế này? – Equixor

+0

@Equixor: Tôi đã đề cập cụ thể hơn đến SqlConnection. Tên lớp của bạn UserDatabase hơi gây nhầm lẫn, bởi vì nó không phải là một cơ sở dữ liệu thực tế. Có lẽ bạn có thể tạo một phương thức có tên GetUsers(), điều đó sẽ trả về một danh sách người dùng. Bài đăng mã thứ hai của bạn là đúng. Giữ chúng xung quanh tồi tệ hơn (và đôi khi dẫn đến khó tái tạo lỗi) –

+0

Ok cảm ơn. Tôi chắc chắn rằng thiết kế tổng thể của điều này cũng có thể được cải thiện. Hầu hết các lớp DAL chúng ta có như thế này và điền các tập dữ liệu mà sau đó được BLL sử dụng. – Equixor