2009-05-19 12 views
5

मैं कुछ सी # 2.0 कोड बनाए रख रहा हूं, और प्रोग्रामर डेटा रीडर खोलकर और फिर ऑब्जेक्ट के कन्स्ट्रक्टर को पास करके व्यावसायिक वस्तुओं के संग्रह को पढ़ने के पैटर्न का उपयोग करता है। मैं इसके साथ कुछ भी गलत नहीं देख सकता, लेकिन यह मेरे लिए बुरा लगता है। क्या यह ठीक है?क्या रचनाकारों को डेटा रीडर पास करना ठीक है?

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

+0

आप इसे कक्षा बनाने के लिए अपना कोड बदल सकते हैं ... :) –

उत्तर

5

ऑब्जेक्ट के कन्स्ट्रक्टर को डेटा रीडर पास करके, आप व्यवसाय ऑब्जेक्ट और दृढ़ता प्रौद्योगिकी की अपनी पसंद के बीच एक बहुत तंग युग्मन स्थापित करते हैं।

कम से कम, यह तंग युग्मन पुन: उपयोग और परीक्षण को कठिन बना देगा; सबसे बुरी स्थिति में, यह परिणामस्वरूप व्यावसायिक वस्तुओं को डेटाबेस के बारे में बहुत ज्यादा जानकारी दे सकता है।

इसे हल करना बहुत मुश्किल नहीं है - आप केवल कन्स्ट्रक्टर से ऑब्जेक्ट प्रारंभिक स्थानांतरित कर सकते हैं और एक विशिष्ट फैक्ट्री क्लास में ले जा सकते हैं।

+3

मुझे लगता है कि विधियों के निर्माता में IDataReader में SqlDataReader को बदलने से यह भी ठीक करने की दिशा में एक लंबा रास्ता तय हो जाता है। IDataReader सामान्य है जो किसी भी अंतर्निहित दृढ़ता प्रौद्योगिकी से बंधे नहीं है। – TheSoftwareJedi

+0

मैं पूरी तरह से सहमत नहीं हूं - जबकि आप कुछ decoupling प्राप्त करते हैं, क्योंकि आप अब एक विशिष्ट कार्यान्वयन पर निर्भर नहीं हैं, आईडीटाइडर पास करने के लिए अभी भी कच्चे ADO.NET का उपयोग करने के लिए आपको बांध रहा है, जैसा कि सिस्टम में करता है। डेटा नामस्थान, किसी भी चीज के उपयोग को रोकना जो उच्च अवशोषण प्रदान करता है (एनएचबीरनेट, इकाई फ्रेमवर्क, लाइटस्पीड, जीनोम इत्यादि)। – Bevan

+0

'IDataReader' काफी जटिल है - आप SqlDataReader के बजाय इसका उपयोग करके लगभग कुछ भी नहीं जीत रहे हैं। 'IDataReader' के साथ आपके पास एकमात्र विकल्प एक अलग ADO.NET प्रदाता के लिए पोर्टेबिलिटी है, जो एक पुल है जिसे आप पास करते समय भी पारित कर सकते हैं - वह विशेष इंटरफ़ेस आपकी परेशानी का सबसे कम होगा। –

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

यह लगभग निश्चित रूप से मैं क्या करूँगा - मुझे यकीन है कि कोई अज्ञात विधियों या लैम्बडा का उपयोग करने का तरीका दिखाएगा। मैं यह देखने के लिए उत्सुक हूं कि यह समाधान कैसे "लोकप्रिय" बनता है। – MikeJ

+0

"का उपयोग कर (SqlDataReader पाठक ..." वास्तव में जरूरी नहीं है, है ना? चूंकि कनेक्शन पहले से ही लपेटा गया है, उस पर निपटान आदेश, कर्सर इत्यादि को साफ करेगा – TheSoftwareJedi

+2

यदि कक्षा IDISposable लागू करती है, तो यह चाहता है आप निपटान को कॉल करने के लिए। इसे निराश न करें। –

1

(संपादित करें: इस सवाल का जवाब पूरी तरह से पर केंद्रित है "क्या कर रहे हैं एक अपेक्षाकृत कम स्तर पर प्रभाव" के बजाय समग्र डिजाइन निहितार्थ ऐसा लगता है कि अन्य उत्तर मिल गया है। कवर किए गए, इसलिए मैं टिप्पणी नहीं करूंगा :)

ठीक है, आपके द्वारा दिए गए कोड के साथ निश्चित रूप से कुछ गड़बड़ है, क्योंकि कनेक्शन, कमांड या रीडर को बंद नहीं किया गया है। विशेष रूप से, अपने कनेक्शन काम लाइन आम तौर पर इस तरह दिखना चाहिए:

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

आप अच्छी तरह से सोच सकते हैं यह सिर्फ लीख उठा रहा है, और यह सिर्फ नमूना कोड और क्लीन-अप महत्वहीन है कि - लेकिन के "स्वामित्व" संसाधन जो सफाई की आवश्यकता है एक निर्माता को DataReader पास करने के साथ ठीक है।

मुझे लगता है कि जब तक आप पाठक के बाद "पाठक" का दस्तावेज करते हैं, तब तक यह ठीक है। उदाहरण के लिए, Image.FromStream में, छवि के बाद स्ट्रीम का मालिक है और आप इसे स्वयं बंद करने के लिए कृपया नहीं ले सकते हैं (छवि प्रारूप और कुछ अन्य चीजों के आधार पर)। दूसरी बार यह बंद करने की आपकी ज़िम्मेदारी अभी भी है। इसे बहुत सावधानीपूर्वक दस्तावेज किया जाना चाहिए, और यदि निर्माता के साथ प्रकार स्वामित्व लेता है, तो सफाई को आवश्यक बनाने के लिए इसे साफ़ करने के लिए साफ-सफाई आसान और बनाने के लिए इसे IDisposable लागू करना चाहिए।

आपके मामले में, ऐसा लगता है कि निर्माता पाठक के स्वामित्व को ले रहा है, जो कि बिल्कुल सही (और सरल) विकल्प है। बस उस दस्तावेज़ को, और कॉलर को अभी भी पाठक को उचित रूप से बंद करना होगा।

+1

कनेक्शन को बंद करने के लिए +1। 'उपयोग' खंड का प्रयोग करें! – TheSoftwareJedi

+0

संपादन के लिए आपत्तियां? क्या मैंने बहुत कुछ जोड़ा? :) – TheSoftwareJedi

+0

मेरे द्वारा ठीक है - मैंने "आमतौर पर" जोड़ा है क्योंकि कुछ दुर्लभ मामले हैं जहां यह थोड़ा अलग तरीके से काम करता है, लेकिन आम तौर पर एक उपयोग कथन जाने का तरीका है। –

1

मैं एक आईडीटाइडर में इकाई को माइऑब्जेक्ट के एड्स परीक्षण के रूप में पास कर दूंगा।

+0

जिज्ञासा से, क्या आपने ऐसा करने की कोशिश की है? मैंने उस पथ को शुरू कर दिया, और जब यह देखा * संभव * IDataReader 'GetSchemaTable' जैसे गंदे बिट्स के साथ एक बहुत बड़ा इंटरफ़ेस है। आपका परीक्षण कोड बड़ा, जटिल, और बनाए रखने में मुश्किल होगा। और आपके द्वारा परीक्षण किए जाने वाले अधिकांश कोड वास्तविक एसक्यूएल डेटाबेस से कड़े बंधे होंगे - और लगभग सभी बग उस युग्मन (लेनदेन, क्वेरी समस्याएं, समय इत्यादि) में होंगे। मैंने फैसला किया कि यह किसी भी तरह से इसके लायक नहीं था। –

+0

अच्छी टिप्पणी। नहीं मैंने नहीं किया है। –

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 होना चाहिए, जिसमें पुनरावृत्ति की अनुमति देने के बजाय संबंधित रिकॉर्ड का परिणाम शामिल है !!

संबंधित मुद्दे