2010-03-04 9 views
22

मेरे पास निम्न कोड है जो dataTable1 और dataTable2 को दो सरल एसक्यूएल प्रश्नों के साथ भरता है, dataTableSqlJoined एक ही टेबल से भरा हुआ है लेकिन एक साथ जुड़ गया है।LINQ के साथ जुड़े दो डेटाटेबल्स से संयुक्त डेटाटेबल बनाएं। सी #

मैं एक LINQ क्वेरी लिखने की कोशिश कर रहा हूं जो dataTableLinqJoined बना सकता है जैसे कि यह SQL का उपयोग करके बनाया गया था। नीचे दिए गए मेरे उदाहरण में, यह केवल डेटाटेबल 1 से मान देता है।

मेरी समस्या यह है कि linq क्वेरी के SELECT में क्या समस्या है। मैं DataRows दोनों से सभी कॉलम युक्त एक नया DataRow कैसे बना सकता हूं। मैं रनटाइम तक क्वेरी के सटीक कॉलम नाम/स्कीमा को नहीं जानूंगा।

sqlCommand = new SqlCommand("SELECT ID, A, B FROM Table1", sqlConnection, sqlTransaction); 
sqlAdapter = new SqlDataAdapter(sqlCommand); 
DataTable dataTable1 = new DataTable(); 
sqlAdapter.Fill(dataTable1); 

sqlCommand = new SqlCommand("SELECT ID, C, D FROM Table2", sqlConnection, sqlTransaction); 
sqlAdapter = new SqlDataAdapter(sqlCommand); 
DataTable dataTable2 = new DataTable(); 
sqlAdapter.Fill(dataTable2); 

sqlCommand = new SqlCommand("SELECT Table1.ID, A, B, Table2.ID, C, D FROM Table1 INNER JOIN Table2 ON Table1.ID = Table2.ID", sqlConnection, sqlTransaction); 
sqlAdapter = new SqlDataAdapter(sqlCommand); 
DataTable dataTableSqlJoined = new DataTable(); 
sqlAdapter.Fill(dataTableSqlJoined); 

var dataRows = 
    from 
     dataRows1 in dataTable1.AsEnumerable() 
    join 
     dataRows2 in dataTable2.AsEnumerable() 
    on 
     dataRows1.Field<int>("ID") equals dataRows2.Field<int>("ID") 
    select 
     dataRows1; // + dataRows2; 

DataTable dataTableLinqJoined = dataRows.CopyToDataTable(); 

कुछ और पृष्ठभूमि के लिए, संयुक्त क्वेरी बहुत डीबी गहन है और प्रदर्शन के मुद्दों का कारण बन रही है। पहली क्वेरी द्वारा लौटाया गया डेटा काफी स्थिर है और इसे अत्यधिक कैश किया जा सकता है। दूसरी क्वेरी द्वारा लौटाया गया डेटा लगातार बदलता है लेकिन दौड़ने के लिए तेज़ होता है और इसलिए उसे कैश करने की आवश्यकता नहीं होती है। संयुक्त डेटाटेबल के पारित होने पर बहुत सारे कोड निर्भर हैं और इसलिए डेटा को अलग प्रारूप में पास करने में कई व्यवहार्य विकल्प उपलब्ध नहीं हैं।

+0

मैं थोड़ा सा उत्सुक हूं कि एक तरफ, आप इन प्रश्नों के प्रदर्शन को बिल्कुल जानते हैं, लेकिन दूसरी तरफ, आप रनटाइम तक तालिका संरचना को नहीं जानते हैं। –

+0

प्रश्न गतिशील रूप से बनाए गए हैं। –

उत्तर

20

क्या आपने अभी तक इस पेज को देखा है?

HOW TO: Implement a DataSet JOIN helper class in Visual C# .NET

अगर ऐसा दृष्टिकोण LINQy आप के लिए पर्याप्त है, तो आप वस्तु विन्यास में, पंक्ति डेटा बाहर तोड़ सकता है नहीं है:

DataTable targetTable = dataTable1.Clone(); 
var dt2Columns = dataTable2.Columns.OfType<DataColumn>().Select(dc => 
    new DataColumn(dc.ColumnName, dc.DataType, dc.Expression, dc.ColumnMapping)); 
targetTable.Columns.AddRange(dt2Columns.ToArray()); 
var rowData = 
    from row1 in dataTable1.AsEnumerable() 
    join row2 in dataTable2.AsEnumerable() 
     on row1.Field<int>("ID") equals row2.Field<int>("ID") 
    select row1.ItemArray.Concat(row2.ItemArray).ToArray(); 
foreach (object[] values in rowData) 
    targetTable.Rows.Add(values); 

मुझे लगता है कि के बारे में के रूप में संक्षिप्त आप करने जा रहे हैं के रूप में है इसे बनाने में सक्षम हो और मैं समझाऊंगा क्यों: यह स्कीमा है।

DataRow एक स्वतंत्र वस्तु नहीं है; यह अपने मालिक DataTable पर निर्भर करता है और इसके बिना नहीं रह सकता है। कोई "डिस्कनेक्ट" DataRow बनाने के लिए कोई समर्थित तरीका नहीं है; CopyToDataTable() विस्तार विधि पंक्तियों पर काम करती है जो पहले से ही DataTable में मौजूद हैं और पंक्तियों की प्रतिलिपि बनाने से पहले स्कीमा को स्रोत से कॉपी करें (याद रखें, प्रत्येक DataRow में अपने माता-पिता Table का संदर्भ है) (संभवतः ImportRow का उपयोग करने की संभावना है, हालांकि मेरे पास नहीं है वास्तव में जांच करने के लिए परावर्तक खोला)।

इस मामले में आपके पास एक नई स्कीमा है जिसे आपको बनाने की आवश्यकता है।इससे पहले कि आप कोई भी (नई) पंक्तियां बना सकें, आपको उन्हें पहले रखने के लिए तालिका बनाने की आवश्यकता है, और इसका मतलब है उपर्युक्त विधि के शीर्ष पर कम से कम 3 पंक्तियों को लिखना।

फिर आप आखिरकार पंक्तियां बना सकते हैं - लेकिन DataTable और उसके संबंधित DataRowCollection एक समय में केवल एक ही समय में एकाधिक पंक्तियों को जोड़ने के लिए किसी भी तरीके का खुलासा नहीं करते हैं। आप, बेशक, अपने खुद के विस्तार विधि जोड़ सकते हैं DataRowCollection इस बनाने के लिए "देखो" अच्छे:

public static void AddRange(this DataRowCollection rc, 
    IEnumerable<object[]> tuples) 
{ 
    foreach (object[] data in tuples) 
     rc.Add(tuples); 
} 

तो फिर तुम पहली विधि में foreach से छुटकारा और के साथ बदलने हो सकता है:

targetTable.Rows.AddRange(rowData); 

हालांकि यह वास्तव में केवल शब्दकोष को स्थानांतरित कर रहा है, इसे समाप्त नहीं कर रहा है।

नीचे की रेखा, जब तक आप विरासत DataSet कक्षा पदानुक्रम के साथ काम कर रहे हैं, वहां हमेशा थोड़ा क्रूर होने वाला होता है। लिंक से डेटासेट एक्सटेंशन अच्छे हैं, लेकिन वे केवल एक्सटेंशन हैं और उपरोक्त सीमाओं को बदल नहीं सकते हैं।

+0

मैंने उस पृष्ठ को देखा था लेकिन इस तथ्य को पसंद नहीं आया कि यह LINQy नहीं था। TargetTable बनाने पर आपका उदाहरण बहुत अच्छा है। धन्यवाद। –

+0

आपके कोड में मामूली संपादन किया गया है, itemarray को संघ की बजाय एक Concat होना चाहिए। अन्यथा यह समान मूल्यों (नल) वाले किसी भी कॉलम को स्ट्रिप्स करता है। हालांकि इसके अलावा। यह पूरी तरह से काम कर रहा है !! धन्यवाद! –

+0

targetTable.Columns.AddRange (dt2Columns.ToArray()); एक ही नाम के साथ फिर से जोड़ने कॉलम के रूप में त्रुटि देता है। – Cannon

0
select new { 
    ID = dataRows1.ID, // no need to select dataRows2.ID, because of JOIN. 
    A = dataRows1.A, 
    B = dataRows1.B, 
    C = dataRows2.C, 
    D = dataRows2.D 
}; 
+0

मुझे रनटाइम तक कॉलम नाम/स्कीमा नहीं पता है। इस प्रकार को डेटाटेबल में बदलने के लिए कोई "सरल" तरीका भी नहीं है। –

+0

इस प्रश्न में स्पॉट नहीं किया था। माफ़ कीजिये। अज्ञात प्रकारों को डेटाटेबल में बदलने के लिए, आप प्रतिबिंब (या अभिव्यक्ति : http://www.infoq.com/articles/expression-compiler) के साथ पागल-पागल सामान कर सकते हैं: –

1

अगर मुझे बेवकूफ़ की तरह लगता है तो मुझे माफ़ कर दो।

मुझे लगता है कि आपके पास अंतिम तालिका तैयार होनी चाहिए (तालिका ए & तालिका बी के सभी फ़ील्ड के साथ)।
और, LINQ का उपयोग करने के बजाय, & में शामिल हों, तो & पर ForEach पर अंतिम डेटाटेबल में मूल्य डालें।

स्यूडोकोड:

dt1.Join (DT2) .Where (...) foreach (पंक्ति => कोड गुमनाम वस्तु & की सामग्री पढ़ने यह finalTable.Rows के लिए जोड़)

+0

मैंने इस तरह कुछ विचार किया था। जैसे संयुक्त क्वेरी चला रहा है लेकिन जुड़ने के बजाय दूसरी क्वेरी से कॉलम में नल डाल रहा है। फिर बस उन्हें पॉप्युलेट करने के लिए दूसरी क्वेरी चला रहा है। उत्तर के लिए +1, लेकिन मैं अभी भी कुछ और "सुरुचिपूर्ण" की उम्मीद कर रहा हूं। –

5

हारून जो महान था। लेकिन आपके LINQY कोड में कुछ एन्हांसमेंट जोड़ना चाहते हैं। डेटाटेबल 2 से लक्ष्य तालिका में कॉलम जोड़ने के दौरान, संभावना होगी कि लक्षित तालिका में कुछ कॉलम पहले ही मौजूद होगा (जिस पर हम शामिल हो रहे हैं)। तो अब हम शुरू करें।

DataTable targetTable = dataTable1.Clone(); 
var dt2Columns = dataTable2.Columns.OfType<DataColumn>().Select(dc => 
new DataColumn(dc.ColumnName, dc.DataType, dc.Expression, dc.ColumnMapping)); 
var dt2FinalColumns=from dc in dt2Columns.AsEnumerable() 
        where targetTable.Columns.Contains(dc.ColumnName) == false 
        select dc; 
targetTable.Columns.AddRange(dt2FinalColumns.ToArray()); 
var rowData =from row1 in dataTable1.AsEnumerable() 
      join row2 in dataTable2.AsEnumerable() 
      on row1.Field<int>("ID") equals row2.Field<int>("ID") 
      select row1.ItemArray.Concat(row2.ItemArray.Where(r2=> row1.ItemArray.Contains(r2)==false)).ToArray(); 
foreach (object[] values in rowData) 
targetTable.Rows.Add(values); 

आशा है कि यह मेरे जैसे लोगों के लिए सहायक होगा।

+0

डिकॉममेंट्स क्या है? – Cannon

+0

dt2Columns में dtcomments बदलें। एक प्रश्न: यदि मेरे पास टॉव टेबल से अधिक शामिल होने के लिए टेबल में मैं कैसे शामिल हो सकता हूं? – Cannon

+0

'वर rowData = row1.Field पर dataTable1.AsEnumerable में ROW1() dataTable2.AsEnumerable (में पंक्ति 2 में शामिल होने) से (" आईडी ") row2.Field (" आईडी ") .AsEnumerable में row3 में शामिल होने के बराबर होती है() ' – suryakiran

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