124

से संग्रहित प्रक्रिया में तालिका मूल्य मानकों को कैसे पास करें I MS SQL Server 2005 डेटाबेस है। कुछ प्रक्रियाओं में मेरे पास टेबल पैरामीटर होते हैं जिन्हें मैं एक संग्रहित प्रो में एक nvarchar (अल्पविराम से अलग) के रूप में पास करता हूं और आंतरिक रूप से एकल मानों में विभाजित होता हूं। मैं इस तरह एसक्यूएल आदेश पैरामीटर सूची में जोड़ने:.net कोड

cmd.Parameters.Add("@Logins", SqlDbType.NVarchar).Value = "jim18,jenny1975,cosmo"; 

मैं एसक्यूएल सर्वर 2008 के लिए डेटाबेस मैं जानता हूँ कि तालिका मान पैरामीटर देखते हैं कि विस्थापित करने के लिए है, और मुझे कैसे संग्रहित प्रक्रियाओं में उन्हें इस्तेमाल करने में पता है। लेकिन मुझे नहीं पता कि SQL कमांड में पैरामीटर सूची में से किसी को कैसे पास किया जाए। क्या कोई Parameters.Add प्रक्रिया का सही सिंटैक्स जानता है? या इस पैरामीटर को पारित करने का कोई और तरीका है?

+0

इस समाधान को देखें: ईएफ में तालिका-मूल्यवान पैरामीटर के साथ संग्रहित प्रक्रिया। https://code.msdn.microsoft.com/Stored-Procedure-with-6c194514 –

+0

इस तरह के मामले में, मैं आम तौर पर स्ट्रिंग को जोड़ता हूं और सर्वर पक्ष पर विभाजित करता हूं या यदि मेरे पास एकाधिक कॉलम हैं तो भी एक xml पास करें। एक्सएमएल प्रोसेस करते समय एसक्यूएल बहुत तेज़ है। आप सभी विधियों का प्रयास कर सकते हैं और प्रसंस्करण समय की जांच कर सकते हैं और उसके बाद सबसे अच्छी विधि चुन सकते हैं। एक एक्सएमएल <आइटम वैल्यू = "sdadas" /><आइटम वैल्यू = "sadsad" /> ... जैसा दिखेगा। एसक्यूएल सर्वर पर प्रक्रिया भी सरल है। इस विधि का उपयोग करते हुए, यदि आपको अधिक जानकारी चाहिए तो आप हमेशा पर एक नई विशेषता जोड़ सकते हैं। –

उत्तर

209

DataTable, DbDataReader, या IEnumerable<SqlDataRecord> वस्तुओं MSDN लेख Table-Valued Parameters in SQL Server 2008 (ADO.NET) प्रति एक तालिका-मान पैरामीटर पॉप्युलेट करने के लिए इस्तेमाल किया जा सकता।

निम्न उदाहरण का उपयोग कर दिखाता है या तो एक DataTable या एक IEnumerable<SqlDataRecord>:

एसक्यूएल कोड:

CREATE TABLE dbo.PageView 
(
    PageViewID BIGINT NOT NULL CONSTRAINT pkPageView PRIMARY KEY CLUSTERED, 
    PageViewCount BIGINT NOT NULL 
); 
CREATE TYPE dbo.PageViewTableType AS TABLE 
(
    PageViewID BIGINT NOT NULL 
); 
CREATE PROCEDURE dbo.procMergePageView 
    @Display dbo.PageViewTableType READONLY 
AS 
BEGIN 
    MERGE INTO dbo.PageView AS T 
    USING @Display AS S 
    ON T.PageViewID = S.PageViewID 
    WHEN MATCHED THEN UPDATE SET T.PageViewCount = T.PageViewCount + 1 
    WHEN NOT MATCHED THEN INSERT VALUES(S.PageViewID, 1); 
END 

सी # कोड:

private static void ExecuteProcedure(bool useDataTable, 
            string connectionString, 
            IEnumerable<long> ids) 
{ 
    using (SqlConnection connection = new SqlConnection(connectionString)) 
    { 
     connection.Open(); 
     using (SqlCommand command = connection.CreateCommand()) 
     { 
      command.CommandText = "dbo.procMergePageView"; 
      command.CommandType = CommandType.StoredProcedure; 

      SqlParameter parameter; 
      if (useDataTable) { 
       parameter = command.Parameters 
           .AddWithValue("@Display", CreateDataTable(ids)); 
      } 
      else 
      { 
       parameter = command.Parameters 
           .AddWithValue("@Display", CreateSqlDataRecords(ids)); 
      } 
      parameter.SqlDbType = SqlDbType.Structured; 
      parameter.TypeName = "dbo.PageViewTableType"; 

      command.ExecuteNonQuery(); 
     } 
    } 
} 

private static DataTable CreateDataTable(IEnumerable<long> ids) 
{ 
    DataTable table = new DataTable(); 
    table.Columns.Add("ID", typeof(long)); 
    foreach (long id in ids) 
    { 
     table.Rows.Add(id); 
    } 
    return table; 
} 

private static IEnumerable<SqlDataRecord> CreateSqlDataRecords(IEnumerable<long> ids) 
{ 
    SqlMetaData[] metaData = new SqlMetaData[1]; 
    metaData[0] = new SqlMetaData("ID", SqlDbType.BigInt); 
    SqlDataRecord record = new SqlDataRecord(metaData); 
    foreach (long id in ids) 
    { 
     record.SetInt64(0, id); 
     yield return record; 
    } 
} 
+14

+1 उत्कृष्ट उदाहरण। टेकवे हैं: 'डेटाटेबल' को पैरामीटर मान के रूप में भेजें, 'SqlDbType' को 'संरचित' और 'टाइपनाम' को डेटाबेस UDT नाम पर सेट करें। –

+7

यदि आप किसी लूप में एक संदर्भ प्रकार का उदाहरण पुन: उपयोग करने जा रहे हैं (आपके उदाहरण में SqlDataRecord), तो कृपया इस विशेष उदाहरण में ऐसा करने के लिए सुरक्षित क्यों है, इस पर एक टिप्पणी जोड़ें। –

+2

यह कोड गलत है: खाली तालिका मूल्यवान मानकों के पास अपना मान 'null' पर सेट होना चाहिए। रिक्त 'ids' पैरामीटर दिए जाने पर 'CreateSqlDataRecords' कभी भी' शून्य 'वापस नहीं करेगा। –

25
इसके अलावा रयान के जवाब देने के लिए

आप करेंगेसेट करने की भी आवश्यकता हैकी Ordinal संपत्ति यदि आप से एकाधिक कॉलम के साथ काम कर रहे हैं, जिनके निर्देशक वर्णमाला क्रम में नहीं हैं।

उदाहरण के लिए, आप निम्न तालिका मूल्य कि SQL में पैरामीटर के रूप में प्रयोग किया जाता है, तो:

CREATE TYPE NodeFilter AS TABLE (
    ID int not null 
    Code nvarchar(10) not null, 
); 

आप सी # में इस तरह के रूप में अपने कॉलम ऑर्डर करने के लिए की आवश्यकता होगी:

table.Columns["ID"].SetOrdinal(0); 
// this also bumps Code to ordinal of 1 
// if you have more than 2 cols then you would need to set more ordinals 

यदि आप ऐसा करने में विफल रहते हैं तो आपको एक पार्स त्रुटि मिल जाएगी, nvarchar को int में कनवर्ट करने में विफल रहा।

13

जेनेरिक

public static DataTable ToTableValuedParameter<T, TProperty>(this IEnumerable<T> list, Func<T, TProperty> selector) 
    { 
     var tbl = new DataTable(); 
     tbl.Columns.Add("Id", typeof(T)); 

     foreach (var item in list) 
     { 
      tbl.Rows.Add(selector.Invoke(item)); 

     } 

     return tbl; 

    } 
+0

क्या आप कृपया मुझे बताएं कि मैं पैरामीटर के रूप में क्या पास करूं? Func <टी, TProperty> चयनकर्ता? क्या यह बस tbl नहीं हो सकता है। पंक्तियां (आइटम) जोड़ें और उस पैरामीटर की कोई आवश्यकता नहीं है। – GDroid

+0

चयनकर्ता। इन्वोक (आइटम) आइटम पर संपत्ति का चयन करता है, ज्यादातर मामलों में यह एक int है, लेकिन यह आपको स्ट्रिंग प्रॉपर्टी – Martea

+0

चुनने की अनुमति देता है, क्या आप कृपया उदाहरण दे सकते हैं कि मैं वहां पर चयनकर्ता कैसे रखूं ?? मेरे पास संग्रहीत proc को पास करने के लिए सूची है ... – GDroid

5

इसके साथ काम करने के लिए स्पष्ट तरीका। अपनी मेज पूर्णांकों "dbo.tvp_Int" कहा जाता है की एक सूची मान लिया जाये कि है (अपनी खुद की तालिका प्रकार के लिए अनुकूलित)

इस विस्तार विधि बनाएं ...

public static void AddWithValue_Tvp_Int(this SqlParameterCollection paramCollection, string parameterName, List<int> data) 
{ 
    if(paramCollection != null) 
    { 
     var p = paramCollection.Add(parameterName, SqlDbType.Structured); 
     p.TypeName = "dbo.tvp_Int"; 
     DataTable _dt = new DataTable() {Columns = {"Value"}}; 
     data.ForEach(value => _dt.Rows.Add(value)); 
     p.Value = _dt; 
    } 
} 

अब आप एक में एक टेबल महत्वपूर्ण पैरामीटर जोड़ सकते हैं लाइन को कहीं भी करके:

cmd.Parameters.AddWithValueFor_Tvp_Int("@IDValues", listOfIds); 
+1

क्या होगा अगर paramCollection पूर्ण है? खाली प्रकार कैसे पास करें? – Muflix

+2

@Muflix अस्पष्ट रूप से, एक्सटेंशन विधियां वास्तव में शून्य उदाहरणों के खिलाफ काम करती हैं। इसलिए विधि के शीर्ष पर एक सरल 'अगर (paramCollection! = Null)' चेक जोड़ना ठीक होगा – Rhumborl

+1

प्रारंभिक -if-check –

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