"ऑब्जेक्ट कोटेक्स्ट उदाहरण को हल किया गया है और उसका समाधान नहीं किया जा सकता।


123

मैं एक GridViewएंटिटी फ्रेमवर्क का उपयोग करने की कोशिश कर रहा हूं, लेकिन हर बार मुझे निम्न त्रुटि मिल रही है:

"संपत्ति एक्सेसर 'लोनप्रोडक्ट' ऑब्जेक्ट पर 'COSIS_DAL.MemberLoan' ने निम्न अपवाद को फेंक दिया: ObjectContext इंस्टेंस को डिस्पोज़ कर दिया गया है और अब उन ऑपरेशनों के लिए उपयोग नहीं किया जा सकता है जिनके लिए कनेक्शन की आवश्यकता होती है।"

मेरा कोड है:

public List<MemberLoan> GetAllMembersForLoan(string keyword)
{
    using (CosisEntities db = new CosisEntities())
    {
        IQueryable<MemberLoan> query = db.MemberLoans.OrderByDescending(m => m.LoanDate);
        if (!string.IsNullOrEmpty(keyword))
        {
            keyword = keyword.ToLower();
            query = query.Where(m =>
                  m.LoanProviderCode.Contains(keyword)
                  || m.MemNo.Contains(keyword)
                  || (!string.IsNullOrEmpty(m.LoanProduct.LoanProductName) && m.LoanProduct.LoanProductName.ToLower().Contains(keyword))
                  || m.Membership.MemName.Contains(keyword)
                  || m.GeneralMasterInformation.Description.Contains(keyword)

                  );
        }
        return query.ToList();
    }
}


protected void btnSearch_Click(object sender, ImageClickEventArgs e)
{
    string keyword = txtKeyword.Text.ToLower();
    LoanController c = new LoanController();
    List<COSIS_DAL.MemberLoan> list = new List<COSIS_DAL.MemberLoan>();
    list = c.GetAllMembersForLoan(keyword);

    if (list.Count <= 0)
    {
        lblMsg.Text = "No Records Found";
        GridView1.DataSourceID = null;
        GridView1.DataSource = null;
        GridView1.DataBind();
    }
    else
    {
        lblMsg.Text = "";
        GridView1.DataSourceID = null;   
        GridView1.DataSource = list;
        GridView1.DataBind();
    }
}

त्रुटि के LoanProductNameकॉलम का उल्लेख कर रहा है Gridview। उल्लेखित: मैं बैक एंड डीबी के रूप में C #, ASP.net, SQL-Server 2008 का उपयोग कर रहा हूं।

मैं एंटिटी फ्रेमवर्क में काफी नया हूं। मुझे समझ नहीं आ रहा है कि मुझे यह त्रुटि क्यों हो रही है। क्या कोई भी कृपया मेरी मदद कर सकता है?


1
क्या आप ग्रिडव्यू में किसी भी नेविगेशन प्रॉपर्टी को एक्सेस कर रहे हैं। यदि आप करते हैं, तो आपको उन नेविगेशन तालिकाओं को क्वेरी में भी शामिल करना होगा। जैसेquery.Include("SomeOtherTable")
नीलेश

अपनी इकाई को होस्ट करने के लिए या कम से कम एक अनाम ऑब्जेक्ट बनाने के लिए एक प्रॉक्सी क्लास बनाने का प्रयास करें। मेरे दृष्टिकोण से, एफई का उपयोग करने के लिए अपने लॉगिक्स को लागू करने के लिए प्रॉक्सी कक्षाएं बनाने की आवश्यकता होती है, एडम्क्स का उपयोग करें जैसे कि डीबी पहुंच परत व्यवसाय के रूप में नहीं।
गोंजिक्स

हाँ ग्रिडव्यू में मुझे एक और टेबल कॉलम भी मिल रहा है। जो LoanProviderName है।
बारां

1
db.MemberLoans.Include("LoanProduct").OrderByDescending()सिंटैक्स की जाँच करने का प्रयास करें क्योंकि मेरे पास वीएस नहीं है मेरे सामने।
नीलेश

3
आपको केवल उन सभी नेविगेशन गुणों को शामिल करने की आवश्यकता है, जिन्हें आप संदर्भ के बाहर एक्सेस कर रहे हैं जैसे db.MemberLoans.Include("LoanProduct").Include("SomeOtherTable)। @Tragedian और @lazyberezovsky
नीलेश

जवाबों:


175

डिफ़ॉल्ट रूप से एंटिटी फ्रेमवर्क नेविगेशन गुणों के लिए आलसी-लोडिंग का उपयोग करता है। इसलिए इन गुणों को आभासी के रूप में चिह्नित किया जाना चाहिए - ईएफ आपकी इकाई के लिए प्रॉक्सी क्लास बनाता है और आलसी-लोडिंग की अनुमति देने के लिए नेविगेशन गुणों को ओवरराइड करता है। जैसे यदि आपके पास यह इकाई है:

public class MemberLoan
{
   public string LoandProviderCode { get; set; }
   public virtual Membership Membership { get; set; }
}

एंटिटी फ्रेमवर्क इस इकाई से विरासत में मिला हुआ प्रॉक्सी लौटाएगा और बाद में सदस्यता के आलसी लोड की अनुमति देने के लिए इस प्रॉक्सी को DbContext उदाहरण प्रदान करेगा:

public class MemberLoanProxy : MemberLoan
{
    private CosisEntities db;
    private int membershipId;
    private Membership membership;

    public override Membership Membership 
    { 
       get 
       {
          if (membership == null)
              membership = db.Memberships.Find(membershipId);
          return membership;
       }
       set { membership = value; }
    }
}

तो, इकाई में DbContext का उदाहरण है जो लोडिंग इकाई के लिए उपयोग किया गया था। यह तुम्हारी समस्या है। आपके पास usingCosisEntities के उपयोग के आसपास ब्लॉक है। संस्थाओं को वापस करने से पहले संदर्भ का निपटान करता है। जब कुछ कोड बाद में आलसी-भारित नेविगेशन संपत्ति का उपयोग करने की कोशिश करते हैं, तो यह विफल हो जाता है, क्योंकि उस समय संदर्भ का निपटान किया जाता है।

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

IQueryable<MemberLoan> query = db.MemberLoans.Include(m => m.Membership);

यह सभी सदस्यों को प्री-लोड करेगा और आलसी-लोडिंग का उपयोग नहीं किया जाएगा। विवरण के लिए MSDN पर लोड हो रहा है संबंधित संबंधित लेख देखें।


आपके उपयोगी स्पष्टीकरण और उत्तर के लिए बहुत बहुत धन्यवाद। वास्तव में यहाँ मैं तीन तालिकाएँ शामिल कर रहा हूँ, इसलिए मुझे नहीं पता कि मैं INCLUDE के साथ तीन तालिकाओं को कैसे जोड़ सकता हूँ। क्या आप कृपया इस पर मेरी मदद कर सकते हैं।
बारसन

8
@ बार्सन में एक-एक करके सभी नेविगेशन गुण शामिल हैं। उदाहरण के db.MemberLoans.Include(m => m.Membership).Include(m => m.LoanProduct).OrderByDescending(m => m.LoanDate);लिए, जोइन क्वेरी उत्पन्न करेगा और एक ही बार में सभी डेटा लौटाएगा।
सर्गेई बेरेज़ोवस्की

1
बहुत बहुत धन्यवाद lazyberezovsky। मैं आपका बहुत आभारी हूं। आपने मुझे लगभग एक दिन बचाया। आपके स्पष्टीकरण से मैं एंटिटी फ्रेमवर्क के बारे में अधिक जान रहा हूँ। धन्यवाद मेरे दोस्त।
बारां

धन्यवाद दोस्त, एकदम सही। मेरे पास एक उपयोग करने वाला बयान था जो आलसी लोडिंग को सीमित कर रहा था। बहुत बढ़िया जवाब।
22

4
क्या होगा यदि मैं अपनी क्वेरी में उन संबंधित संस्थाओं को शामिल नहीं करना चाहता हूं?
ऑर्टुंड

32

CosisEntitiesवर्ग अपने है DbContext। जब आप किसी usingब्लॉक में एक संदर्भ बनाते हैं , तो आप अपने डेटा-उन्मुख ऑपरेशन के लिए सीमाओं को परिभाषित कर रहे हैं।

आपके कोड में, आप किसी विधि से किसी क्वेरी के परिणाम का उत्सर्जन करने का प्रयास कर रहे हैं और फिर विधि के भीतर संदर्भ समाप्त कर सकते हैं। ग्रिड दृश्य को पॉप्युलेट करने के लिए आप जिस ऑपरेशन को परिणाम देते हैं, उसके बाद संस्थाओं तक पहुँचने की कोशिश करता है। कहीं न कहीं ग्रिड से जुड़ने की प्रक्रिया में, एक आलसी-भरी संपत्ति तक पहुँचा जा रहा है और एंटिटी फ्रेमवर्क मूल्यों को प्राप्त करने के लिए एक खोज करने की कोशिश कर रहा है। यह विफल हो जाता है, क्योंकि संबंधित संदर्भ पहले ही समाप्त हो चुका है।

आपको दो समस्याएं हैं:

  1. जब आप ग्रिड से जुड़ते हैं तो आप आलसी-लोडिंग इकाइयाँ होते हैं। इसका मतलब है कि आप SQL सर्वर पर बहुत सारे अलग-अलग क्वेरी ऑपरेशन कर रहे हैं, जो सब कुछ धीमा कर रहे हैं। आप संबंधित समस्याओं को डिफ़ॉल्ट रूप से संबंधित-लोडेड बनाकर या एंटिटी फ्रेमवर्क को Includeएक्सटेंशन विधि का उपयोग करके उन्हें इस क्वेरी के परिणामों में शामिल करने के लिए कहकर इस समस्या को ठीक कर सकते हैं ।

  2. आप अपने संदर्भ को समय से पहले समाप्त कर रहे हैं: DbContextप्रदर्शन किए जा रहे कार्य की पूरी इकाई में उपलब्ध होना चाहिए, केवल तब ही निपटाना जब आप काम को हाथ से कर रहे हों। ASP.NET के मामले में, कार्य की एक इकाई आमतौर पर HTTP अनुरोध को संभाला जा रहा है।


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

20

जमीनी स्तर

आपके कोड ने आलसी-लोडिंग सक्षम के साथ इकाई-ढांचे के माध्यम से डेटा (निकाय) को पुनः प्राप्त कर लिया है और DbContext के निपटान के बाद, आपका कोड गुणों (संबंधित / संबंध / नेविगेशन संस्थाओं) को संदर्भित कर रहा है जो स्पष्ट रूप से अनुरोध नहीं किया गया था।

अधिक विशेष रूप से

InvalidOperationExceptionइस संदेश के साथ हमेशा एक ही बात मतलब है: के बाद DbContext निपटारा कर दिया गया है आप इकाई-ढांचे से डेटा (संस्थाओं) अनुरोध कर रहे हैं।

एक साधारण मामला:

(इन कक्षाओं का उपयोग इस उत्तर में सभी उदाहरणों के लिए किया जाएगा, और मान लें कि सभी नेविगेशन गुणों को सही तरीके से कॉन्फ़िगर किया गया है और डेटाबेस में संबंधित टेबल हैं)

public class Person
{
  public int Id { get; set; }
  public string name { get; set; }
  public int? PetId { get; set; }
  public Pet Pet { get; set; }
}

public class Pet 
{
  public string name { get; set; }
}

using (var db = new dbContext())
{
  var person = db.Persons.FirstOrDefaultAsync(p => p.id == 1);
}

Console.WriteLine(person.Pet.Name);

अंतिम पंक्ति को फेंक देगा InvalidOperationExceptionक्योंकि dbContext ने आलसी-लोडिंग को अक्षम नहीं किया है और कोड का उपयोग कर स्टेटमेंट को निपटाने के बाद पालतू नेविगेशन संपत्ति तक पहुंच रहा है।

डिबगिंग

आप इस अपवाद का स्रोत कैसे खोजते हैं? अपवाद को देखने के अलावा, जो बिल्कुल उस स्थान पर फेंक दिया जाएगा जहां यह होता है, विजुअल स्टूडियो में डिबगिंग के सामान्य नियम लागू होते हैं: रणनीतिक ब्रेकपॉइंट्स लगाएं और अपने चर का निरीक्षण करें , या तो उनके नामों पर माउस मँडराकर, एक को खोलकर ( क्विक) विंडो देखें या लोकल और ऑटो जैसे विभिन्न डिबगिंग पैनल का उपयोग करें।

यदि आप यह जानना चाहते हैं कि संदर्भ कहाँ है या सेट नहीं है, तो उसके नाम पर राइट-क्लिक करें और "सभी संदर्भ खोजें" चुनें। फिर आप प्रत्येक स्थान पर एक ब्रेकपॉइंट रख सकते हैं जो डेटा का अनुरोध करता है, और अपने प्रोग्राम को डिबगर संलग्न के साथ चलाएं। हर बार जब डिबगर इस तरह के ब्रेकपॉइंट पर टूटता है, तो आपको यह निर्धारित करने की आवश्यकता है कि क्या आपकी नेविगेशन संपत्ति आबाद होनी चाहिए या यदि अनुरोध किया गया डेटा आवश्यक है।

बचने के तरीके

आलसी लोडिंग को अक्षम करें

public class MyDbContext : DbContext
{
  public MyDbContext()
  {
    this.Configuration.LazyLoadingEnabled = false;
  }
}

पेशेवरों: InvalidOperationException को फेंकने के बजाय संपत्ति शून्य होगी। नल की संपत्तियों तक पहुँचने या इस संपत्ति के गुणों को बदलने का प्रयास एक NullReferenceException को फेंक देगा ।

जरूरत पड़ने पर वस्तु का स्पष्ट रूप से अनुरोध कैसे करें:

using (var db = new dbContext())
{
  var person = db.Persons
    .Include(p => p.Pet)
    .FirstOrDefaultAsync(p => p.id == 1);
}
Console.WriteLine(person.Pet.Name);  // No Exception Thrown

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

या

using (var db = new dbContext())
{
  var person = db.Persons.FirstOrDefaultAsync(p => p.id == 1);

  var pet = db.Pets.FirstOrDefaultAsync(p => p.id == person.PetId);
}
Console.WriteLine(person.Pet.Name);  // No Exception Thrown

पिछले उदाहरण में, एंटिटी फ्रेमवर्क डेटाबेस से एक अतिरिक्त कॉल करके व्यक्ति को स्वतंत्र रूप से पालतू बना देगा। डिफ़ॉल्ट रूप से, एंटिटी फ्रेमवर्क उन वस्तुओं को ट्रैक करता है जिन्हें डेटाबेस से पुनर्प्राप्त किया गया है और अगर यह नेविगेशन गुणों को खोजता है जो इसे स्वचालित रूप से अपनी संस्थाओं को पॉप्युलेट करेगा । इस उदाहरण में, क्योंकि PetIdपर Personवस्तु से मेल खाता है Pet.Id, इकाई की रूपरेखा प्रदान करेंगे Person.Petकरने के लिए Petलिया गया मूल्य, इससे पहले कि मूल्य पालतू चर को सौंपा गया है।

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


13

यह बहुत देर से जवाब है, लेकिन मैंने आलसी लोडिंग को बंद करने वाले मुद्दे को हल किया:

db.Configuration.LazyLoadingEnabled = false;

मेरे लिए, StackOverflow एक लाइनर के साथ अद्भुत काम करता है। और यह मेरे लिए किया, आप के लिए यश!
हेरोल्ड_फिंच

नकारात्मक पक्ष यह है कि आपको उपयोग करना होगा। नेविगेशन गुणों को लोड करने के लिए इस तरह की चीजों और चीजों को छोड़ दें।
boylec1986

1

मेरे मामले में, मैं सभी मॉडलों के उपयोगकर्ताओं को कॉलम के लिए पास कर रहा था और इसे सही ढंग से मैप नहीं किया गया था, इसलिए मैंने अभी 'Users.Name' पास किया और इसे ठीक कर दिया।

var data = db.ApplicationTranceLogs 
             .Include(q=>q.Users)
             .Include(q => q.LookupItems) 
             .Select(q => new { Id = q.Id, FormatDate = q.Date.ToString("yyyy/MM/dd"), ***Users = q.Users,*** ProcessType = q.ProcessType, CoreProcessId = q.CoreProcessId, Data = q.Data }) 
             .ToList();

var data = db.ApplicationTranceLogs 
             .Include(q=>q.Users).Include(q => q.LookupItems) 
             .Select(q => new { Id = q.Id, FormatDate = q.Date.ToString("yyyy/MM/dd"), ***Users = q.Users.Name***, ProcessType = q.ProcessType, CoreProcessId = q.CoreProcessId, Data = q.Data }) 
             .ToList();

1

अधिकांश अन्य उत्तर उत्सुक लोडिंग की ओर इशारा करते हैं, लेकिन मुझे एक और समाधान मिला।

मेरे मामले में मेरे पास बाल वस्तुओं के InventoryItemसंग्रह के साथ एक ईएफ ऑब्जेक्ट था InvActivity

class InventoryItem {
...
   // EF code first declaration of a cross table relationship
   public virtual List<InvActivity> ItemsActivity { get; set; }

   public GetLatestActivity()
   {
       return ItemActivity?.OrderByDescending(x => x.DateEntered).SingleOrDefault();
   }
...
}

और जब से मैं एक संदर्भ क्वेरी (के साथ IQueryable) के बजाय चाइल्ड ऑब्जेक्ट संग्रह से खींच रहा था , Include()उत्सुक लोडिंग को लागू करने के लिए फ़ंक्शन उपलब्ध नहीं था। इसलिए इसके बजाय मेरा समाधान एक संदर्भ बनाना था जहां से मैंने उपयोग किया GetLatestActivity()और attach()लौटाई गई वस्तु:

using (DBContext ctx = new DBContext())
{
    var latestAct = _item.GetLatestActivity();

    // attach the Entity object back to a usable database context
    ctx.InventoryActivity.Attach(latestAct);

    // your code that would make use of the latestAct's lazy loading
    // ie   latestAct.lazyLoadedChild.name = "foo";
}

इस प्रकार आप उत्सुक लोडिंग के साथ फंस नहीं रहे हैं।


यह मूल रूप से उत्सुक लोडिंग है, आपने ऑब्जेक्ट को एक संदर्भ के माध्यम से लोड किया है। केवल दो विकल्प हैं; उत्सुक लोड हो रहा है और आलसी लोड हो रहा है।
एरिक फिलिप्स

@ ErikPhilips सही है, यह एक नए डेटा संदर्भ के साथ आलसी लोड हो रहा है
Zorgarath

1
@ErikPhilips - स्पष्ट लोड हो रहा है - docs.microsoft.com/en-us/ef/ef6/querying/…
डेव ब्लैक

1

यदि आप ASP.NET कोर का उपयोग कर रहे हैं और आश्चर्य है कि आपको अपने async नियंत्रक विधियों में से एक में यह संदेश क्यों मिलता है, तो सुनिश्चित करें कि आप Taskइसके बजाय वापस लौटेंvoid - ASP.NET Core इंजेक्शन इंजेक्ट करता है।

(मैं इस उत्तर को पोस्ट कर रहा हूं क्योंकि यह प्रश्न उस अपवाद संदेश के खोज परिणामों में उच्च है और यह एक सूक्ष्म मुद्दा है - शायद यह उन लोगों के लिए उपयोगी है जो इसके लिए Google हैं।)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.