2009-01-12 7 views
8

हाल ही में मैं अपने आप को डेटा का उपयोग परत का चयन तरीकों जहां कोड सब यह सामान्य रूप लेता लिख ​​पाते हैं सुधार करने के लिए कैसे:डेटा का उपयोग परत का चयन विधि पैटर्न

public static DataTable GetSomeData(... arguments) 
{ 
    string sql = " ... sql string here: often it's just a stored procedure name ... "; 

    DataTable result = new DataTable(); 

    // GetOpenConnection() is a private method in the class: 
    // it manages the connection string and returns an open and ready connection 
    using (SqlConnection cn = GetOpenConnection()) 
    using (SqlCommand cmd = new SqlCommand(sql, cn)) 
    { 
     // could be any number of parameters, each with a different type 
     cmd.Parameters.Add("@Param1", SqlDbType.VarChar, 50).Value = param1; //argument passed to function 

     using (SqlDataReader rdr = cmd.ExecuteReader()) 
     { 
      result.Load(rdr); 
     } 
    } 

    return result; 
} 

या इस तरह:

public static DataRow GetSomeSingleRecord(... arguments) 
{ 
    string sql = " ... sql string here: often it's just a stored procedure name ... "; 

    DataTable dt = new DataTable(); 

    // GetOpenConnection() is a private method in the class: 
    // it manages the connection string and returns an open and ready connection 
    using (SqlConnection cn = GetOpenConnection()) 
    using (SqlCommand cmd = new SqlCommand(sql, cn)) 
    { 
     // could be any number of parameters, each with a different type 
     cmd.Parameters.Add("@Param1", SqlDbType.VarChar, 50).Value = param1; //argument passed to function 

     using (SqlDataReader rdr = cmd.ExecuteReader(CommandBehavior.SingleRow)) 
     { 
      dt.Load(rdr); 
     } 
    } 

    if (dt.Rows.Count > 0) 
     return dt.Rows[0]; 
    return null; 
} 

इन विधियों को बिजनेस लेयर कोड द्वारा बुलाया जाएगा जो तब बेस डेटाटेबल या डेटा रिकॉर्डॉर्ड को दृढ़ता से टाइप की गई व्यावसायिक ऑब्जेक्ट्स में परिवर्तित करता है जो प्रस्तुति स्तर का उपयोग कर सकते हैं।

चूंकि मैं बार-बार समान कोड का उपयोग कर रहा हूं, इसलिए मैं यह सुनिश्चित करना चाहता हूं कि यह कोड सबसे अच्छा हो। तो यह कैसे सुधार किया जा सकता है? और, क्या यह सामान्य कोड को अपनी विधि से बाहर ले जाने की कोशिश करने लायक है। यदि हां, तो यह तरीका कैसा दिखता है (विशेष रूप से एसकल्प पैरामीटर संग्रह को पास करने के संबंध में)?

+0

आप इस मैं क्या बस के रूप में करते हैं। बहुत बढ़िया! एक चीज जिसमें मुझे रूचि है, यह है कि आप अपने बीएएल बनाम अपने डीएएल बनाम तर्कसंगत रूप से/phyiscally कैसे सेट करते हैं - क्या आप इसे अपनी परियोजना में डालते हैं? या नामस्थान के रूप में? और क्या? – dfasdljkhfaskldjhfasklhf

+0

यदि कोई पैरामीटर नहीं है तो आप डेटरेडर को भी ढेर कर सकते हैं। डीएएल अपनी स्वयं की असेंबली में है, डीएएल + बीएल एक आम पेरेंट नेमस्पेस साझा करेगा। –

+0

हां यह है कि मैं इसे कैसे करता हूं। व्यावसायिक वस्तुओं और डीएएल वस्तुओं के बीच आपका मानचित्रण क्या है? यानी आप 1: 1 जाते हैं? एक बात जो मैंने दिलचस्प देखी वह वह व्यक्ति था जिसने व्यापारिक वस्तु में डीएएल खींच लिया और इसे कोडस्मिथ के साथ बाहर निकाला। बहुत रोचक – dfasdljkhfaskldjhfasklhf

उत्तर

1

केवल एक चीज मैं अलग तरीके से करते मैं अपने खुद के आंतरिक डाटाबेस सहायक तरीकों से वास्तविक डेटा एक्सेस आवेदन ब्लॉक http://msdn.microsoft.com/en-us/library/cc309504.aspx

यह अन्य डेवलपर्स जो उद्यम पुस्तकालय पता बढ़ाना के लिए एक छोटे से अधिक मानकीकृत/वर्दी बनाता है पर स्विच किया है कोड पर ऊपर। के रूप में ग्राहक कोड चला जाता है

2

एक पैटर्न मैं आनंद लिया है के रूप में अब तक इस तरह दिखता है:

 DataTable data = null; 
     using (StoredProcedure proc = new StoredProcedure("MyProcName","[Connection]")) 
     { 
      proc.AddParameter("@LoginName", loginName); 
      data = proc.ExecuteDataTable(); 
     } 

मैं आमतौर पर कनेक्शन वैकल्पिक बनाने, और मैं एक तरह से कोड ConnectionStrings config अनुभाग से खींच न ही इसके इलाज के लिए होगा वास्तविक कनेक्शन स्ट्रिंग के रूप में। यह मुझे एक ऑफ परिदृश्य में दाल का पुन: उपयोग करने देता है और जब मैं ऑब्जेक्ट निर्माण संपत्ति का उपयोग कर कनेक्शन स्ट्रिंग संग्रहीत करता हूं तो COM + दिनों से एक खरगोश भाग लेता है।

मुझे यह पसंद है क्योंकि यह मेरे द्वारा सभी एडीओ कोड को पढ़ने और छिपाने में आसान है।

+0

मुझे इसके साथ कुछ समस्याएं हैं, लेकिन अपवॉट क्योंकि यह मुझे एक विचार देता है: मैं एक विधि के बजाय एक सामान्य फंक्शन के रूप में सामान्य कोड को छिपाने के साथ खेलना चाहता हूं। –

+0

दिलचस्प कृपया साझा करें कि आप किसके साथ आते हैं। मुझे इस पैटर्न पर बेचा नहीं गया है, यह अभी तक 2.0 पर है। और यह अव्यवस्था को कम करता है – JoshBerke

+0

ध्यान दें कि मैंने कहा "play": मुझे नहीं लगता कि मैं उस मार्ग पर जाउंगा। अगर मैं कुछ दिलचस्प के साथ आता हूं तो मैं इसे वापस पोस्ट करूंगा। –

1

डीबीएएल को लागू करने के कई तरीके हैं, मेरी राय में आप सही रास्ते पर हैं। Somethings अपने कार्यान्वयन में विचार करने के लिए:

  • आपको फ़ैक्टरी की तरह विधि का उपयोग कर रहे हैं अपने SqlConnection बनाने के लिए, यह एक छोटी सी बात है, लेकिन आप अपने SqlCommand के लिए भी ऐसा ही कर सकते हैं।
  • पैरामीटर लंबाई वैकल्पिक है, इसलिए आप इसे वास्तव में पैरामीटर से बाहर छोड़ सकते हैं। कॉल जोड़ें।
  • पैरामीटर जोड़ने के लिए विधियां भी बनाएं, नीचे कोड नमूना।

का उपयोग कर DbUtil.AddParameter(cmd, "@Id", SqlDbType.UniqueIdentifier, Id);

internal class DbUtil { 

internal static SqlParameter CreateSqlParameter(
    string parameterName, 
    SqlDbType dbType, 
    ParameterDirection direction, 
    object value 
) { 
    SqlParameter parameter = new SqlParameter(parameterName, dbType); 

    if (value == null) { 
     value = DBNull.Value; 
    } 

    parameter.Value = value; 

    parameter.Direction = direction; 
    return parameter; 
} 

internal static SqlParameter AddParameter(
    SqlCommand sqlCommand, 
    string parameterName, 
    SqlDbType dbType 
) { 
    return AddParameter(sqlCommand, parameterName, dbType, null); 
} 

internal static SqlParameter AddParameter(
    SqlCommand sqlCommand, 
    string parameterName, 
    SqlDbType dbType, 
    object value 
) { 
    return AddParameter(sqlCommand, parameterName, dbType, ParameterDirection.Input, value); 
} 

internal static SqlParameter AddParameter(
    SqlCommand sqlCommand, 
    string parameterName, 
    SqlDbType dbType, 
    ParameterDirection direction, 
    object value 
) { 
    SqlParameter parameter = CreateSqlParameter(parameterName, dbType, direction, value); 
    sqlCommand.Parameters.Add(parameter); 
    return parameter; 
    } 
} 
1

पहले पैरामीटर जोड़ें, मैं आप पहले से ही अपने स्वयं के रोलिंग बनाम एक ORM का उपयोग कर माना जाता है। मैं इस में नहीं जाऊंगा।

अपने खुद के डेटा एक्सेस कोड रोलिंग पर मेरे विचार:

    समय के साथ
  • , मैं यह आसान अलग दाल/बीएल वस्तुओं के लिए नहीं, बल्कि एक भी वस्तु में उन्हें बाद में विलय (कुछ समय तक पहुंचने के बाद पाया इस निष्कर्ष में मुझे पता चला कि यह एक बहुत प्रसिद्ध ज्ञात पैटर्न है - अर्थात ActiveRecord)। यह अलग-अलग डीएएल असेंबली रखने के लिए अच्छा और decoupled लग सकता है, लेकिन रखरखाव लागत में ओवरहेड जोड़ देगा। हर बार जब आप एक नई सुविधा जोड़ते हैं, तो आपको अधिक कक्षाएं/अधिक कक्षाएं संशोधित करना होगा।मेरे अनुभव में, टीम जो अनुप्रयोग को बनाए रखती है वह अक्सर डेवलपर्स की मूल टीम से कम होती है जो इसे निर्मित करती है, और वे आवश्यक अतिरिक्त काम से नफरत करेंगे।
  • बड़ी टीमों के लिए, यह अपने विशिष्ट नमूना करने के लिए नीचे आ रहा है समझ में दाल अलग करने के लिए कर सकता है (और उस पर एक समूह में काम करते हैं, जबकि दूसरों लेकिन यह एक अच्छा प्रोत्साहन कोड ब्लोट के लिए बनाता है
  • :।। आप कैसे करते हैं परिणामस्वरूप डेटाटेबल का उपयोग करें? पंक्तियों को दोहराएं, टाइप की गई वस्तुओं को बनाएं और पंक्ति से डेटा प्राप्त करें? अगर उत्तर हाँ है, तो आपने डीएएल और बीएल के बीच डेटा को स्थानांतरित करने के लिए बनाए गए अतिरिक्त डेटाटेबल के बारे में सोचें। इसे सीधे क्यों न लें DataReader?
  • इसके अलावा नमूना के बारे में: यदि आप एक अवांछित डेटाटेबल लौटाते हैं, तो मुझे लगता है कि आपको कॉलम नामों का उपयोग करना होगा (परिणामस्वरूप एसपी कॉल रिटर्न सेट करें) कॉलिंग कोड में रास्ता है। इसका मतलब है कि मेरे पास है डेटाबेस में कुछ बदलने के लिए, यह दोनों परतों को प्रभावित कर सकता है।

मेरा सुझाव (मैंने दोनों तरीकों की कोशिश की - सुझाव नवीनतम कामकाजी दृष्टिकोण है जिसके साथ मैं आया - यह समय के साथ विकसित हुआ)।

  • अपनी टाइप की गई व्यावसायिक वस्तुओं के लिए बेस क्लास बनाएं।
  • बेस क्लास (नया, संशोधित इत्यादि) में ऑब्जेक्ट स्टेटस रखें
  • इस वर्ग में स्थिर डेटा विधियों के रूप में मुख्य डेटा एक्सेस विधियां रखें। थोड़ा प्रयास (संकेत: जेनेरिक तरीकों + एक्टिवेटर। क्रिएट इंस्टेंस) के साथ आप पाठक में लौटाई गई प्रत्येक पंक्ति के लिए एक व्यावसायिक वस्तु बना सकते हैं।
  • पंक्ति डेटा को पार्स करने के लिए व्यावसायिक ऑब्जेक्ट में एक सार विधि बनाएं (सीधे डेटा रीडर से!) और ऑब्जेक्ट भरें।
  • व्युत्पन्न व्यावसायिक वस्तुओं में स्थैतिक तरीकों को बनाते हैं जो संग्रहित प्रो पैरामीटर तैयार करते हैं (विभिन्न फ़िल्टर मानदंडों के आधार पर) और बेस क्लास से जेनेरिक डेटा एक्सेस विधियों को कॉल करते हैं।

    List<MyObject> objects = MyObject.FindMyObject(string someParam); 
    

    मेरे लिए लाभ था मैं केवल क्रम में एक फ़ाइल को बदलने के लिए डेटाबेस कॉलम नामों के परिवर्तन से निपटने के लिए है, प्रकार:

उद्देश्य जैसे उपयोग के साथ खत्म करने के लिए है आदि (सामान्य रूप से छोटे बदलाव)। कुछ अच्छी तरह से विचार क्षेत्रों के साथ, आप कोड व्यवस्थित कर सकते हैं ताकि वे एक ही ऑब्जेक्ट में अलग "परतें" हों :)। दूसरा लाभ यह है कि आधार वर्ग वास्तव में एक परियोजना से दूसरे प्रोजेक्ट में पुन: प्रयोज्य है। और कोड ब्लोट कम से कम है (अच्छी तरह से, लाभों की तुलना में। आप डेटासेट भी भर सकते हैं और उन्हें यूआई नियंत्रण में जोड़ सकते हैं: डी

सीमाएं - आप एक डोमेन प्रति डोमेन ऑब्जेक्ट (आमतौर पर प्रति मुख्य डेटाबेस तालिका) के साथ समाप्त होते हैं। और आप मौजूदा लेनदेन में ऑब्जेक्ट्स लोड नहीं कर सकते हैं (हालांकि आप लेनदेन पर गुजरने के बारे में सोच सकते हैं, यदि आपके पास कोई है)

मुझे बताएं कि क्या आप अधिक जानकारी में रूचि रखते हैं - मैं जवाब का विस्तार कर सकता हूं बिट।

3

जोड़ने के लिए था मेरे अपने:
Return DataReader from DataLayer in Using statement

नए पैटर्न मुझे सक्षम बनाता है एक बार में केवल स्मृति में एक रिकॉर्ड है, लेकिन अभी भी एक अच्छा 'का उपयोग' बयान में कनेक्शन encases:

public IEnumerable<T> GetSomeData(string filter, Func<IDataRecord, T> factory) 
{ 
    string sql = "SELECT * FROM [SomeTable] WHERE SomeColumn= @Filter"; 

    using (SqlConnection cn = new SqlConnection(GetConnectionString())) 
    using (SqlCommand cmd = new SqlCommand(sql, cn)) 
    { 
     cmd.Parameters.Add("@Filter", SqlDbType.NVarChar, 255).Value = filter; 
     cn.Open(); 

     using (IDataReader rdr = cmd.ExecuteReader()) 
     { 
      while (rdr.Read()) 
      { 
       yield return factory(rdr); 
      } 
      rdr.Close(); 
     } 
    } 
} 
+0

आपकी छोड़कर हैंडलिंग कहां है? – msfanboy

+9

@msfanboy - जहां यह –

+0

प्रोग्राम में उच्च स्तर पर है, वैसे भी, यह अब पुराना है। मैंने तब से पैटर्न को आगे बढ़ाया है: http://stackoverflow.com/questions/2862428/fastest-method-for-sql-server-inserts-updates-selects/2862490#2862490 –

1

क्या मैं पोस्ट here

public IEnumerable<S> Get<S>(string query, Action<IDbCommand> parameterizer, 
          Func<IDataRecord, S> selector) 
{ 
    using (var conn = new T()) //your connection object 
    { 
     using (var cmd = conn.CreateCommand()) 
     { 
      if (parameterizer != null) 
       parameterizer(cmd); 
      cmd.CommandText = query; 
      cmd.Connection.ConnectionString = _connectionString; 
      cmd.Connection.Open(); 
      using (var r = cmd.ExecuteReader()) 
       while (r.Read()) 
        yield return selector(r); 
     } 
    } 
} 

मैं सहायता करने के लिए इन सरल विस्तार के तरीकों के लिए इसी प्रकार के तो अब

public static void Parameterize(this IDbCommand command, string name, object value) 
{ 
    var parameter = command.CreateParameter(); 
    parameter.ParameterName = name; 
    parameter.Value = value; 
    command.Parameters.Add(parameter); 
} 

public static T To<T>(this IDataRecord dr, int index, T defaultValue = default(T), 
         Func<object, T> converter = null) 
{ 
    return dr[index].To<T>(defaultValue, converter); 
} 

static T To<T>(this object obj, T defaultValue, Func<object, T> converter) 
{ 
    if (obj.IsNull()) 
     return defaultValue; 

    return converter == null ? (T)obj : converter(obj); 
} 

public static bool IsNull<T>(this T obj) where T : class 
{ 
    return (object)obj == null || obj == DBNull.Value; 
} 

मैं कॉल कर सकते हैं: बुलाने की आसानी

var query = Get(sql, cmd => 
{ 
    cmd.Parameterize("saved", 1); 
    cmd.Parameterize("name", "abel"); 
}, r => new User(r.To<int>(0), r.To<string>(1), r.To<DateTime?>(2), r.To<bool>(3))); 
foreach (var user in query) 
{ 

} 

यह पूरी तरह से सामान्य है, किसी भी मॉडल है कि ado.net इंटरफेस का पालन फिट बैठता है। The connection object and reader is disposed only after the collection is enumerated once.

-1

सरल समाधान: - हालांकि मैं वास्तव में की तरह कैसे आप अपने दोहरे बयानों का उपयोग कर ढेर गहरी घोंसले से बचने के लिए

var dt=new DataTable(); 
dt.Load(myDataReader); 
list<DataRow> dr=dt.AsEnumerable().ToList(); 
+0

यह पूरी तरह से बिंदु को याद करता है। यहां भी सबसे धीमी उत्तर देने की संभावना है, क्योंकि यह रैम में पूरे परिणाम को केवल एक बार नहीं, बल्कि दो बार लोड करता है। –

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