2009-11-17 15 views
5

मुझे एक इकाई फ्रेमवर्क LINQ क्वेरी बनाने में समस्या हो रही है जिसका चयन खंड गैर-ईएफ ऑब्जेक्ट्स में विधि कॉल करता है।गैर-ईएफ विधि कॉल वाले खंड का चयन करें

नीचे दिया गया कोड एक डीबीएमएस से डेटा को दूसरे डीबीएमएस पर एक अलग स्कीमा में बदलने के लिए उपयोग किए जाने वाले ऐप का हिस्सा है। नीचे दिए गए कोड में, भूमिका डीबीएमएस के लिए अपने कस्टम वर्ग से संबंधित नहीं है, और अन्य वर्गों के सभी मेरी DB स्कीमा से इकाई की रूपरेखा द्वारा उत्पन्न कर रहे:

// set up ObjectContext's for Old and new DB schemas 
var New = new NewModel.NewEntities(); 
var Old = new OldModel.OldEntities(); 

// cache all Role names and IDs in the new-schema roles table into a dictionary 
var newRoles = New.roles.ToDictionary(row => row.rolename, row => row.roleid); 

// create a list or Role objects where Name is name in the old DB, while 
// ID is the ID corresponding to that name in the new DB 
var roles = from rl in Old.userrolelinks 
      join r in Old.roles on rl.RoleID equals r.RoleID 
      where rl.UserID == userId 
      select new Role { Name = r.RoleName, ID = newRoles[r.RoleName] }; 
var list = roles.ToList(); 

लेकिन ToList बुला मुझे इस NotSupportedException देता है:

संस्थाओं को

LINQ विधि 'Int32 get_Item (System.String)' विधि, और इस विधि को नहीं पहचानता है में अनुवाद नहीं किया जा सकता है एक दुकान अभिव्यक्ति

LINQ-to-Entities की तरह लगता है कि नाम को कुंजी के रूप में दिए गए शब्द से बाहर खींचने के लिए मेरे कॉल पर बारफिंग है। मैं स्वीकार करता हूं कि ईएफ के बारे में पर्याप्त जानकारी नहीं है यह जानने के लिए कि यह एक समस्या क्यों है।

मैं devart के dotConnect for PostgreSQL इकाई ढांचे प्रदाता का उपयोग कर रहा हूं, हालांकि मुझे लगता है कि यह एक डीबीएमएस-विशिष्ट मुद्दा नहीं है।

मैं जानता हूँ कि मैं इसे इस तरह दो प्रश्नों में अपनी क्वेरी ऊपर विभाजित करके काम करते हैं, कर सकते हैं:

var roles = from rl in Old.userrolelinks 
      join r in Old.roles on rl.RoleID equals r.RoleID 
      where rl.UserID == userId 
      select r; 
var roles2 = from r in roles.AsEnumerable() 
      select new Role { Name = r.RoleName, ID = newRoles[r.RoleName] }; 
var list = roles2.ToList(); 

लेकिन अगर वहाँ था इस समस्या को हल करने के लिए एक और अधिक सुरुचिपूर्ण और/या अधिक कारगर तरीका मैं सोच रहा था आदर्श रूप से इसे दो प्रश्नों में विभाजित किए बिना।

वैसे भी, मेरे सवाल का दो भागों है:

पहले, मैं कुछ है कि इकाई की रूपरेखा दो टुकड़ों में, स्वीकार करेंगे आदर्श बंटवारे के बिना में इस LINQ क्वेरी बदल सकता है?

दूसरा, मुझे ईएफ के बारे में कुछ भी समझना अच्छा लगेगा, इसलिए मैं समझ सकता हूं कि ईएफ डीबी एक्सेस के शीर्ष पर मेरे कस्टम .NET कोड को क्यों नहीं ले सकता है। मेरे डीबीएमएस को कोई एहसास नहीं है कि डिक्शनरी क्लास पर एक विधि कैसे कॉल करें, लेकिन डीएफ से डेटा खींचने के बाद ईएफ बस उन डिक्शनरी कॉल कॉल क्यों नहीं कर सकता है? निश्चित रूप से, अगर मैं एक साथ कई ईएफ प्रश्नों को लिखना चाहता हूं और बीच में कस्टम .NET कोड डालना चाहता हूं, तो मैं असफल होने की उम्मीद करता हूं, लेकिन इस मामले में .NET कोड केवल अंत में है, तो यह एक समस्या क्यों है एफई? मुझे लगता है कि जवाब कुछ ऐसा है जैसे "उस सुविधा ने इसे ईएफ 1.0 में नहीं बनाया है" लेकिन मैं थोड़ा और स्पष्टीकरण की तलाश कर रहा हूं कि यह ईएफ 1.0 से बाहर निकलने के लिए उचित क्यों है।

उत्तर

10

समस्या यह है कि लिंक के देरी निष्पादन का उपयोग करने में, आपको वास्तव में यह तय करना होगा कि आप कहां प्रसंस्करण चाहते हैं और आप अपने क्लाइंट एप्लिकेशन में पाइप को किस डेटा को पार करना चाहते हैं। पहले उदाहरण में, Linq अभिव्यक्ति हल करता है और उस समय

New.roles.ToDictionary(row => row.rolename, row => row.roleid); 

करने के लिए एक अग्रदूत के रूप में भूमिका डेटा के सभी खींचती है, ग्राहक में डीबी से डेटा ले जाता है और अपने शब्दकोश में तब्दील हो जाता। अब तक सब ठीक है.

समस्या यह है कि अपने दूसरे Linq अभिव्यक्ति दूसरा डीबी डीबी पर शब्दकोश का उपयोग कर ऐसा करने के लिए पर परिणत करने के लिए Linq पूछ रहा है है।दूसरे शब्दों में, यह संपूर्ण शब्दकोश संरचना को डीबी में पास करने का एक तरीका जानने का प्रयास कर रहा है ताकि वह क्वेरी के देरी निष्पादन के हिस्से के रूप में सही आईडी मान का चयन कर सके। मुझे लगता है कि यह अगर तुम

var roles = from rl in Old.userrolelinks 
      join r in Old.roles on rl.RoleID equals r.RoleID 
      where rl.UserID == userId 
      select r.RoleName; 
var list = roles.ToDictionary(roleName => roleName, newRoles[roleName]); 

इस तरह के दूसरी छमाही बदल ठीक हल होगा संदेह है, यह ToDictionary कॉल (प्रसंस्करण के लिए एक अग्रदूत के रूप डीबी पर अपने चयन को हल करता है (बस rolename का चयन), जो यह होना चाहिए जैसा कि आप उम्मीद करेंगे ग्राहक पर करें)। यह अनिवार्य रूप से वही है जो आप अपने दूसरे उदाहरण में कर रहे हैं क्योंकि AsNumerable डेटा को टोलिस्ट कॉल में उपयोग करने से पहले क्लाइंट को खींच रहा है। आप इसे आसानी से

var roles = from rl in Old.userrolelinks 
      join r in Old.roles on rl.RoleID equals r.RoleID 
      where rl.UserID == userId 
      select r; 
var list = roles.AsEnumerable().Select(r => new Role { Name = r.RoleName, ID = newRoles[r.RoleName] }); 

पर आसानी से बदल सकते हैं और यह वही काम करेगा। AsEnumerable() को कॉल क्वेरी का समाधान करता है, जो क्लाइंट को डेटा का उपयोग करने के लिए चयन में उपयोग के लिए खींचता है।

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

+0

लगता है जैसे मैंने LINQ से इकाइयों के स्मारकों को अधिक महत्व दिया। मैंने माना था कि एल-टू-ई एक अभिव्यक्ति वृक्ष को उस हिस्से में विघटित करने के लिए पर्याप्त स्मार्ट था जिसे डीबी संभाल सकता है, और एक अन्य भाग जिसे इसे .NET कॉल (डीबी के बाहर) का उपयोग करके हल करना था, और फिर दोनों को सिलाई करना साथ में। अगर मैं आपको सही ढंग से समझता हूं, तो आप कह रहे हैं कि एल-टू-ई वह स्मार्ट नहीं है - यह बस एसक्यूएल में अभिव्यक्ति में * सबकुछ * को बदलने की कोशिश करता है, और अगर ऐसा कुछ है तो यह परिवर्तित नहीं हो सकता है (उदाहरण के लिए चयन खंड में .NET ऑब्जेक्ट विधि पर कॉल करें), तो यह निष्पादित करने में विफल रहेगा? –

+1

यह जस्टिन सही है। नोट: स्वचालित रूप से सभी स्तरों पर एक क्वेरी को विच्छेदन करना, एक 'वितरित क्वेरी' है, जो आम तौर पर हल करने के लिए एक अविश्वसनीय रूप से कठिन समस्या है। –

+0

दाएं। LINQ से इकाइयों में सब कुछ एक अभिव्यक्ति वृक्ष के रूप में होता है जो अंततः डेटाबेस के खिलाफ उपयोग करेगा जब यह * वास्तव में * पुनरावृत्त होता है। यह उस तरह से "गूंगा" है, लेकिन ऐसा इसलिए है क्योंकि, जैसा कि एलेक्स कहता है, वितरित प्रश्न हल करने के लिए एक अविश्वसनीय रूप से कठिन समस्या है जब चीजें थोड़ा जटिल हो जाती हैं। पता है कि, हालांकि, आप डेटा को क्लाइंट को खींचने के लिए अपने बुकमार्क के रूप में पुनरावृत्ति का उपयोग कर सकते हैं। –

3

याकूब पूरी तरह से सही है। आप वांछित क्वेरी को दो भागों में विभाजित किए बिना बदल नहीं सकते हैं, क्योंकि इकाई फ्रेमवर्क SQL क्वेरी में get_Item कॉल का अनुवाद करने में असमर्थ है।
एकमात्र तरीका LINQ से Entities क्वेरी लिखना है और उसके बाद जैकब ने सलाह दी है कि इसके परिणामस्वरूप ऑब्जेक्ट क्वेरी में LINQ लिखें।
समस्या इकाई-फ्रेमवर्क-विशिष्ट है, यह इकाई फ्रेमवर्क समर्थन के हमारे कार्यान्वयन से उत्पन्न नहीं होती है।

+0

+1। त्वरित प्रतिक्रिया के लिए धन्यवाद - विक्रेताओं को उनके कोड से संबंधित सवालों के जवाब देने के लिए कूदने के लिए अच्छा लगा! –

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