2009-05-19 40 views
5

我正在維護一些C#2.0代碼,程序員通過打開一個DataReader然後將它傳遞給該對象的構造函數來使用一種讀取業務對象集合的模式。我看不出有什麼明顯的錯誤,但對我來說感覺很糟糕。這可以嗎?將DataReader傳遞給構造函數可以嗎?

private static void GetObjects() 
{ 
    List<MyObject> objects = new List<MyObject>(); 
    string sql = "Select ..."; 
    SqlConnection connection = GetConnection(); 
    SqlCommand command = new SqlCommand(sql, connection); 
    connection.Open(); 
    SqlDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection); 
    while (reader.Read()) 
     objects.Add(new MyObject(reader)); 
    reader.Close(); 
} 

public MyObject(SqlDataReader reader) 
{ 
    field0 = reader.GetString(0); 
    field1 = reader.GetString(1); 
    field2 = reader.GetString(2); 
} 
+0

我的例子並不清楚,但假設MyObject是一個單獨的類。 – Sisiutl 2009-05-19 22:59:32

+0

你可以改變你的代碼,使其成爲一個類:) :) – 2009-05-19 23:02:56

回答

5

通過將DataReader傳遞給對象的構造函數,您可以在業務對象和您選擇的持久性技術之間建立非常緊密的耦合。

至少,這種緊密的耦合將使複用和測試變得困難;最糟糕的是,這可能會導致業務對象對數據庫瞭解過多。

解決這個問題並不困難 - 只需將對象初始化移出構造函數並移入不同的工廠類即可。

1

我不會這樣做,但我沒有看到任何重大錯誤。

3

通過讀者使我感到畏縮,除非它是處理複製一行的非公開輔助方法。絕對不是給構造函數。

傳遞讀者連接你的構造函數(你沒有把MyObject放在類中,但是你調用new MyObject())到你的數據存儲中,我推測你的對象不是這樣寫的?

如果是我的話:

private static void GetObjects() 
{ 
    List<MyObject> objects = new List<MyObject>(); 
    string sql = "Select ..."; 
    using (SqlConnection connection = GetConnection()) 
    { 
     SqlCommand command = new SqlCommand(sql, connection); 
     connection.Open(); 
     using(SqlDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection);) 
     { 
      while (reader.Read()) 
       objects.Add(_ReadRow(reader)); 
     } 
    } 
} 

private static MyObject _ReadRow(SqlDataReader reader) 
{ 
    MyObject o = new MyObject(); 
    o.field0 = reader.GetString(0); 
    o.field1 = reader.GetString(1); 
    o.field2 = reader.GetString(2); 

    // Do other manipulation to object before returning 

    return o; 
} 

class MyObject{} 
+0

這幾乎可以肯定我會做什麼 - 我相信有人會展示一種方法來使用匿名方法或lambda表達式。我很好奇看到這個解決方案如何「流行」。 – MikeJ 2009-05-19 23:16:01

+0

「使用(SqlDataReader reader ...」並不是真的需要,對嗎?由於連接已經被封裝,所以配置會清理命令,遊標等。 – TheSoftwareJedi 2009-05-20 00:03:21

+2

如果類實現了IDisposable,那麼它希望你可以調用Dispose,不要讓它失望 – 2009-05-20 01:23:37

1

(編輯:這個答案完全着眼於「什麼都在相對較低水平的影響」,而不是整體設計影響它看起來像其他的答案已經得到。那些覆蓋,所以我不會評論:)

那麼,肯定有錯誤的代碼,因爲沒有關閉連接,命令或讀者。具體來說,您的連接分配的線路通常應該是這樣的:

using (SqlConnection connection = GetConnection()) 
{ 
    ... 
} 

你可能認爲這只是吹毛求疵,那它只是示例代碼和清理不重要 - 但是的「所有權」 需要的資源清理正是將DataReader傳遞給構造函數的問題。

只要你記錄誰擁有讀者之後,我認爲沒關係。例如,在Image.FromStream中,圖像擁有之後的流,並且可能不會友好地關閉它(取決於圖像格式和其他一些內容)。其他時候,您仍然有責任關閉。這必須非常仔細地記錄下來,如果帶有構造函數的類型取得所有權,則應該執行IDisposable以使清理更容易使其更明顯需要清理。

在你的情況,它看起來像構造函數是而不是取得讀者的所有權,這是一個非常好(和更簡單)的選擇。簡單地記錄下來,並且調用者仍然必須適當地關閉閱讀器。

1

我會使實體在IDataReader中傳遞,因爲這有助於MyObject的測試。

1

我稱之爲「泄漏抽象」。

我喜歡在可能的最窄範圍內使用持久對象:獲取它們,使用它們,清理它們。如果存在明確定義的持久對象,則可以要求它將查詢結果映射到對象或集合中,關閉方法範圍內的讀取器,並將對象或集合返回給客戶端。

0

我完全duffymo(+1)(貝文和)同意

一個想法我一直在咀嚼最近在我的心裏,如果我必須有一個相關性,當然,當我映射讀者對象我必須有一個依賴,也許我應該使之完全明確,實際上寫的擴展方法來實現它,像...

//This Static extension class in the same namespace (but not necesarrily assembly) as my BO 

public static class DataReaderExtensions 
{ 
    public static List<MyObject> GetMyObjects(this DataReader reader) 
    { 

    } 
} 

這樣一來,只要我在這是我的業務對象的參考範圍,我的數據搜索器現在將有一種適合我需求的方法......這個想法可能需要更充實,但我認爲這將是優雅的。

0

要獨立的業務和數據層使用收益

public IEnumerable<IDataReader> getIDataReader(string sql) 
{ 

    using (SqlConnection conn = new SqlConnection("cadena de conexion")) 
    { 
     using (SqlCommand da = new SqlCommand(sql, conn)) 
     { 
      conn.Open(); 
      using (SqlDataReader dr = da.ExecuteReader) 
      { 
       if (dr.HasRows) 
       { 
        while (dr.Read) 
        { 
         yield return dr; 
        } 
       } 
      } 
      conn.Close(); 
     } 
    } 
} 
0

傳遞數據讀寫器的構造可能是有爭議的,但 - 據我所知 - 是一個衆所周知的方法。但是,使用它的人應該通過抽象,即不是SqlDataReader而是IDataReader。然而IDataReader並不是最優的。它應該是IDataRecord,而不是允許迭代!

相關問題