2012-11-29 22 views
28

त्रुटि का निपटारा किया गया है, मैं ईएफ के लिए नया हूं और मैं एक विस्तार विधि का उपयोग करने की कोशिश कर रहा हूं जो मेरे डेटाबेस प्रकार User से मेरी जानकारी कक्षा UserInfo में परिवर्तित हो जाता है।
यदि मैं कोई फर्क पड़ता हूं तो मैं डेटाबेस का उपयोग कर रहा हूं? नीचेऑपरेशन पूरा नहीं किया जा सकता है क्योंकि DbContext को

मेरे कोड त्रुटि क्योंकि DbContext निपटारा कर दिया गया है

कार्रवाई पूर्ण नहीं किया जा सकता है देता है।

try 
{ 
    IQueryable<User> users; 
    using (var dataContext = new dataContext()) 
    { 
     users = dataContext.Users 
        .Where(x => x.AccountID == accountId && x.IsAdmin == false); 
     if(users.Any() == false) 
     { 
      return null; 
     } 
    } 
    return users.Select(x => x.ToInfo()).ToList(); // this line is the problem 
} 
catch (Exception ex) 
{ 
    //... 
} 

मैं देख सकता हूँ क्यों यह यह करना होगा, लेकिन मैं यह भी समझ में नहीं आता क्यों का परिणाम जहां बयान users वस्तु में सहेजा नहीं जा रहा है?

तो मुझे लगता है कि मेरा मुख्य प्रश्न यह है कि यह क्यों काम नहीं करता है और दूसरा, एक्सटेंशन विधियों और ईएफ का उपयोग करने का सही तरीका क्या है?

उत्तर

29

यह question & answer मुझे विश्वास दिलाता है कि IQueryable को इसके संचालन के लिए एक सक्रिय संदर्भ की आवश्यकता है। इसका मतलब है कि आप इस के बजाय प्रयास करना चाहिए:

try 
{ 
    IQueryable<User> users; 

    using (var dataContext = new dataContext()) 
    { 
     users = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false); 

     if(users.Any() == false) 
     { 
      return null; 
     } 
     else 
     { 
      return users.Select(x => x.ToInfo()).ToList(); // this line is the problem 
     } 
    } 


} 
catch (Exception ex) 
{ 
    ... 
} 
+1

धन्यवाद का उपयोग करके अंदर लिखने की आवश्यकता है। अब मैं देख सकता हूं कि IQueryable वह जगह है जहां मैं परेशानी में भाग रहा हूं। यदि मैं उपयोगकर्ताओं को डालता हूं। उपयोग() ... लाइन का उपयोग कथन में करें, यह मुझे एक और त्रुटि देता है (मुझे लगता है कि अलग सवाल)। तो मैंने वापसी प्रकार को IENumerable के रूप में बदल दिया और इसने मेरी समस्या हल कर दी है। – Colin

+0

धन्यवाद यह मेरे लिए काम किया गया है और अब मुझे पता चला है कि IQueryable आवश्यक सक्रिय DBContext –

2

कारण है कि यह त्रुटि फेंक है वस्तु निपटान किया जाता है और उसके बाद हम वस्तु के माध्यम से तालिका मूल्यों का उपयोग करने की कोशिश कर रहे हैं, लेकिन वस्तु को disposed.Better है इसे ToList() में परिवर्तित करें ताकि हमारे पास मूल्य

हो सकता है कि वास्तव में यह तब तक डेटा प्राप्त नहीं हो रहा जब तक आप इसका उपयोग न करें (यह आलसी लोडिंग हो), इसलिए जब आप काम करने की कोशिश कर रहे हैं तो डेटा कॉन्टेक्स्ट मौजूद नहीं है । मैं शर्त लगाता हूं कि आपने टोस्टिस्ट() को दायरे में किया है तो यह ठीक रहेगा।

try 
{ 
    IQueryable<User> users; 
    var ret = null; 

    using (var dataContext = new dataContext()) 
    { 
     users = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false); 

     if(users.Any()) 
     { 
      ret = users.Select(x => x.ToInfo()).ToList(); 
     } 

    } 

    Return ret; 
} 
catch (Exception ex) 
{ 
    ... 
} 
22

वस्तुओं IQueryable<T> के रूप में सामने आ रहा है और IEnumerable<T> वास्तव में "अमल" नहीं है, जब तक वे अधिक दोहराया जाता है या अन्यथा इस तरह के एक List<T> में बना जा रहा है के रूप में, पहुँचा। जब ईएफ IQueryable<T> देता है तो यह अनिवार्य रूप से केवल डेटा पुनर्प्राप्त करने में सक्षम कुछ लिख रहा है, यह वास्तव में तब तक पुनर्प्राप्त नहीं कर रहा है जब तक आप इसे उपभोग नहीं करते।

आप ब्रेकपॉइंट डालकर इसके लिए एक महसूस कर सकते हैं जहां IQueryable परिभाषित किया गया है, बनाम जब .ToList() कहा जाता है। (डेटा संदर्भ के दायरे के अंदर से जोफ्री ने सही ढंग से बताया है।) डेटा खींचने का काम ToList() कॉल के दौरान किया जाता है।

इसके कारण, आपको डेटा संदर्भ के दायरे में IQueryable<T> रखना होगा।

12

आपको यह याद रखना होगा कि IQueryable क्वेरी वास्तव में डेटा स्टोर के विरुद्ध निष्पादित नहीं की जाती हैं जब तक कि आप उन्हें गणना न करें।

using (var dataContext = new dataContext()) 
{ 

कोड की यह पंक्ति वास्तव में अन्य कुछ नहीं करता से SQL विवरण

users = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false); 

.Any() का निर्माण एक ऑपरेशन IQueryable विश्लेषण करता है, तो SQL डेटा को भेजा जाता है स्रोत (डेटा कॉन्टेक्स्ट के माध्यम से), और उसके बाद।किसी भी() के संचालन के खिलाफ यह

if(users.Any() == false) 
    { 
     return null; 
    } 
} 

आपका "समस्या" लाइन एसक्यूएल ऊपर बनाया पुन: उपयोग किया जाता है, और फिर एक अतिरिक्त कार्रवाई करते समय मार डाला जाता है (.Select()) है, जो पूछताछ में केवल कहते हैं। आप इसे यहाँ, कोई अपवाद नहीं, बाएँ आपकी समस्या को लाइन

return users.Select(x => x.ToInfo()).ToList(); // this line is the problem 

कॉल .ToList() है, जो IQueryable विश्लेषण करता है, जो DataContext के माध्यम से डेटा स्रोत है कि मूल में इस्तेमाल किया गया था के लिए भेजा जाना एसक्यूएल का कारण बनता है को छोड़कर अगर LINQ क्वेरी। चूंकि इस डेटा कॉन्टेक्स्ट का निपटारा किया गया है, यह अब मान्य नहीं है, और। टोस्टिस्ट() एक अपवाद फेंकता है।

यह "यह क्यों काम नहीं करता" है। फिक्स कोड के इस लाइन को अपने डेटा कॉन्टेक्स्ट के दायरे में ले जाना है।

इसका उपयोग कैसे करें ठीक से आपके आवेदन पर निर्भर कुछ तर्कसंगत सही उत्तरों के साथ एक और सवाल है (फॉर्म बनाम एएसपीनेट बनाम एमवीसी, आदि)। पैटर्न जो यह उपकरण कार्य पैटर्न की इकाई है। एक नया संदर्भ वस्तु बनाने के लिए लगभग कोई लागत नहीं है, इसलिए सामान्य नियम एक बनाना है, अपना काम करें, और उसके बाद इसका निपटान करें। वेब ऐप्स में, कुछ लोग प्रति अनुरोध एक संदर्भ बनायेंगे।

+0

सिंगलऑर्डडिल्ट() भी इसी तरह की समस्या का कारण बनता है – code4j

0

यह आपके भंडार में ToList() जोड़ने के समान सरल हो सकता है। उदाहरण के लिए:

public IEnumerable<MyObject> GetMyObjectsForId(string id) 
{ 
    using (var ctxt = new RcContext()) 
    { 
     // causes an error 
     return ctxt.MyObjects.Where(x => x.MyObjects.Id == id); 
    } 
} 

बुला कक्षा में Db प्रसंग निपटारा त्रुटि निकलेगा लेकिन यह स्पष्ट रूप से LINQ संचालन पर ToList() जोड़कर गणना व्यायाम द्वारा हल किया जा कर सकते हैं:

public IEnumerable<MyObject> GetMyObjectsForId(string id) 
{ 
    using (var ctxt = new RcContext()) 
    { 
     return ctxt.MyObjects.Where(x => x.MyObjects.Id == id).ToList(); 
    } 
} 
1

इस बदलें :

using (var dataContext = new dataContext()) 
{ 
    users = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false); 

    if(users.Any()) 
    { 
     ret = users.Select(x => x.ToInfo()).ToList(); 
    } 

} 
इस के लिए

:

using (var dataContext = new dataContext()) 
{ 
    return = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false).Select(x => x.ToInfo()).ToList(); 
} 

यह बात यह है कि आप केवल एक बार संदर्भ डेटासेट की गणना को मजबूर करना चाहते हैं। कॉलर को खाली सेट परिदृश्य के साथ सौदा करने दें, जैसा कि उन्हें करना चाहिए।

1

यहां आप निष्क्रिय DBContext पर IQueryable ऑब्जेक्ट निष्पादित करने का प्रयास कर रहे हैं। आपका डीबीकोनटेक्स्ट पहले ही निपट चुका है। डीबीसीएन्टेक्स्ट का निपटान करने से पहले आप केवल IQueryable ऑब्जेक्ट निष्पादित कर सकते हैं। इसका मतलब है कि आपको users.Select(x => x.ToInfo()).ToList() स्कोप