2008-10-16 14 views
50

मुझे अक्सर डेटाबेस में किसी विशेष रिकॉर्ड में एकाधिक आइटम लोड करना पड़ता था। उदाहरण के लिए: एक वेब पेज एक रिपोर्ट के लिए शामिल करने के लिए आइटम प्रदर्शित करता है, जिनमें से सभी डेटाबेस में रिकॉर्ड हैं (रिपोर्ट रिपोर्ट तालिका में एक रिकॉर्ड है, आइटम आइटम तालिका में रिकॉर्ड हैं)। एक उपयोगकर्ता वेब ऐप के माध्यम से एक ही रिपोर्ट में शामिल करने के लिए आइटम का चयन कर रहा है, और मान लीजिए कि वे 3 आइटम का चयन करें और जमा करें। प्रक्रिया इन 3 आइटमों को ReportItems (ReportId, ItemId) नामक तालिका में रिकॉर्ड जोड़कर इस रिपोर्ट में जोड़ देगी। संग्रहित प्रक्रिया मेंउत्तीर्ण सूची <> एसक्यूएल संग्रहीत प्रक्रिया

public void AddItemsToReport(string connStr, int Id, List<int> itemList) 
{ 
    Database db = DatabaseFactory.CreateDatabase(connStr); 

    string sqlCommand = "AddItemsToReport" 
    DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand); 

    string items = ""; 
    foreach (int i in itemList) 
     items += string.Format("{0}~", i); 

    if (items.Length > 0) 
     items = items.Substring(0, items.Length - 1); 

    // Add parameters 
    db.AddInParameter(dbCommand, "ReportId", DbType.Int32, Id); 
    db.AddInParameter(dbCommand, "Items", DbType.String, perms); 
    db.ExecuteNonQuery(dbCommand); 
} 

और इस:

वर्तमान में, मैं कुछ इस तरह का कोड में करना होगा

INSERT INTO ReportItem (ReportId,ItemId) 
SELECT @ReportId, 
      Id 
FROM  fn_GetIntTableFromList(@Items,'~') 

कहाँ समारोह पूर्णांकों का एक एक स्तंभ तालिका देता है। वहाँ एक बेहतर तरीका कुछ इस तरह संभाल करने के लिए है:

मेरा प्रश्न है? ध्यान दें, मैं डेटाबेस सामान्यीकरण या उसके जैसा कुछ भी नहीं पूछ रहा हूं, मेरा प्रश्न विशेष रूप से कोड से संबंधित है।

उत्तर

5

आप या तो कर क्या आप पहले से ही मिल गया है, एक सीमांकित स्ट्रिंग में पारित और फिर एक मेज मूल्य के लिए बाहर पार्स, या अन्य विकल्प एक्सएमएल के wodge में गुजर रहा है और थोड़े ज्यादा एक ही:

http://weblogs.asp.net/jgalloway/archive/2007/02/16/passing-lists-to-sql-server-2005-with-xml-parameters.aspx

मुझे अभी तक यह देखने का मौका नहीं मिला है कि उन्होंने इस प्रकार की चीज़ को संभालने के लिए कोई नई कार्यक्षमता जोड़ दी है या नहीं।

19

आपका स्ट्रिंग में शामिल होने के तर्क शायद सरल किया जा सकता:

string items = 
    string.Join("~", itemList.Select(item=>item.ToString()).ToArray()); 

है कि आप कुछ स्ट्रिंग संयोजन है, जो नेट में महंगा है बचत होगी।

मुझे नहीं लगता कि कुछ भी जिस तरह से आप आइटम बचत कर रहे हैं के साथ गलत है। आप डीबी के लिए यात्रा सीमित कर रहे हैं, जो एक अच्छी बात है। यदि आपकी डेटा संरचना इन्ट्स की सूची से अधिक जटिल थी, तो मैं एक्सएमएल का सुझाव दूंगा।

नोट: मुझे टिप्पणियों में पूछा गया था कि इससे हमें कोई स्ट्रिंग कॉन्सटेनेशन (यह इंडीड किया जाएगा) बचाएगा। मुझे लगता है कि यह एक उत्कृष्ट सवाल है और उस पर अनुवर्ती करना चाहते हैं।

यदि आप खुले स्ट्रिंग को छीलते हैं। Reflector के साथ जुड़ें आप देखेंगे कि माइक्रोसॉफ्ट कुछ असुरक्षित (शब्द की नेट समझ में) तकनीकों का उपयोग कर रहा है, जिसमें एक चार सूचक और UnSafeCharBuffer नामक संरचना शामिल है। वे क्या कर रहे हैं, जब आप इसे वास्तव में उबालते हैं, तो पॉइंटर्स का उपयोग खाली स्ट्रिंग पर चलने और जुड़ने के लिए किया जाता है। याद रखें कि मुख्य कारण स्ट्रिंग कॉन्सटेनेशन इतना महंगा है। नेट यह है कि हर कंसल्टेशन के लिए ढेर पर एक नई स्ट्रिंग ऑब्जेक्ट रखी जाती है, क्योंकि स्ट्रिंग अपरिवर्तनीय है। उन स्मृति संचालन महंगे हैं। String.Join (..) अनिवार्य रूप से एक बार स्मृति आवंटित कर रहा है, फिर एक सूचक के साथ इसे ऑपरेटिंग। बहुत तेज़।

+0

कि वास्तव में संयोजन से आप को बचाने के लिए जा रहा है? क्या आपको पता है कि स्ट्रिंगबिल्डर का उपयोग करके विधि लागू की गई थी? –

+0

हां, यह आपको concatenation से बचाएगा। String.Join एक असुरक्षितखफर का उपयोग करने के लिए कॉन्सट (रिफ्लेक्टर में इसे देखें) का उपयोग करता है। जहां तक ​​LINQ चला जाता है, यह सिर्फ ToString() को कॉल करने वाली सूची में उल्लिखित है, जो अपरिहार्य है, और एक सरणी बना रहा है। सरणी निर्माण महंगा हो सकता है। –

+0

मुझे नहीं पता था कि आप इसे ऐसा कर सकते हैं, टिप के लिए धन्यवाद! –

8

आपकी तकनीक के साथ एक संभावित समस्या यह है कि यह बहुत बड़ी सूचियों को संभाल नहीं पाती है - आप अपने डेटाबेस के लिए अधिकतम स्ट्रिंग लंबाई से अधिक हो सकते हैं।

public static IEnumerable<string> ConcatenateValues(IEnumerable<int> values, string separator, int maxLength, bool skipDuplicates) 
{ 
    IDictionary<int, string> valueDictionary = null; 
    StringBuilder sb = new StringBuilder(); 
    if (skipDuplicates) 
    { 
     valueDictionary = new Dictionary<int, string>(); 
    } 
    foreach (int value in values) 
    { 
     if (skipDuplicates) 
     { 
      if (valueDictionary.ContainsKey(value)) continue; 
      valueDictionary.Add(value, ""); 
     } 
     string s = value.ToString(CultureInfo.InvariantCulture); 
     if ((sb.Length + separator.Length + s.Length) > maxLength) 
     { 
      // Max length reached, yield the result and start again 
      if (sb.Length > 0) yield return sb.ToString(); 
      sb.Length = 0; 
     } 
     if (sb.Length > 0) sb.Append(separator); 
     sb.Append(s); 
    } 
    // Yield whatever's left over 
    if (sb.Length > 0) yield return sb.ToString(); 
} 

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

using(SqlCommand command = ...) 
{ 
    command.Connection = ...; 
    command.Transaction = ...; // if in a transaction 
    SqlParameter parameter = command.Parameters.Add("@Items", ...); 
    foreach(string itemList in ConcatenateValues(values, "~", 8000, false)) 
    { 
     parameter.Value = itemList; 
     command.ExecuteNonQuery(); 
    } 
} 
+1

अच्छा बिंदु, मैंने स्ट्रिंग की लंबाई को पार करने के बारे में सोचा नहीं था। हालांकि मुझे संदेह है कि मेरे पास ऐसे मामले होंगे जो करीब आते हैं, यह सीखना अच्छा होता है, धन्यवाद! –

2

इस मुद्दे की विस्तृत चर्चा और विभिन्न दृष्टिकोणों कि आप इस्तेमाल कर सकते हैं के लिए http://www.sommarskog.se/arrays-in-sql-2005.html देखें।

34

में एकाधिक मान के लिए एक एकल फील्ड तो एसक्यूएल सर्वर 2008 के लिए जा रहा आप के लिए एक विकल्प है, वहाँ एक नई सुविधा "टेबल-मान पैरामीटर" कहा जाता है इस का समाधान करने के लिए सटीक समस्या

टीवीपी here और here पर अधिक जानकारी देखें या केवल "SQL सर्वर 2008 तालिका-मूल्यवान पैरामीटर" के लिए Google से पूछें - आपको बहुत सारी जानकारी और नमूने मिलेंगे।

अत्यधिक की सिफारिश की - यदि आप एसक्यूएल सर्वर 2008 के लिए स्थानांतरित कर सकते हैं ...

5

क्यों एक मेज-मान पैरामीटर का उपयोग नहीं? http://msdn.microsoft.com/en-us/library/bb675163.aspx

+0

क्योंकि इसे उपयोगकर्ता परिभाषित तालिका प्रकार की आवश्यकता होती है, जो स्थायी रूप से डीबी में रह सकती है जबतक कि आप गारंटी न दें कि आप प्रत्येक आमंत्रण के बाद इस प्रकार को हटा दें। – alpav

+0

क्या यह एक समस्या है? – GaTechThomas

+0

उदाहरण के लिए आपको लाइव तैनाती में बदलावों को स्क्रिप्ट करना है, तो उन्हें प्रबंधित करना मुश्किल होता है। – philw

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