Entity Framework 5 нетърпеливо зареждане с родителски свойства

Имам заявка за някакъв родителски обект (Order) и искам да заредя някои от неговите подколекции или свойства с нетърпение. Имам запитване като това:

public void QueryMethod()
{
    using (var context = new MyContext())
    {
        var orders = context.Order.Include("OrderProduct")
                                  .Include("OrderProduct.ProductVariant")
                                  .Where(some query)
                                  .ToList();
    }
}

Това, което правя, е да преминавам през тази колекция от поръчки и за всяко Order достигам до OrderProduct и ProductVariant свойства. Мога да направя това вътре в метода на заявката, когато контекстът е жив. Но когато се опитам да осъществя достъп до ProductVariant.OrderProduct извън контекста, получавам ObjectDisposedException.

Между другото, опитвам се да получа достъп до ProductVariant.OrderProduct по някаква странна причина. Мисля, че не трябва да осъществявам достъп до него по този начин, но искам да кажа, че мога да достигна от OrderProduct до ProductVariant, но не мога да осъществя достъп от ProductVariant до OrderProduct. Чудя се защо получавам тази грешка, въпреки че добавих OrderProduct.ProductVariant в свойствата си за нетърпеливо зареждане. Не трябва ли да работи и в двете посоки?

Всяка помощ ще бъде много оценена.


person ayk    schedule 27.09.2013    source източник
comment
Това картографиране 1:1 ли е?   -  person Gert Arnold    schedule 27.09.2013
comment
Съпоставянето става по следния начин: Order to OrderProduct 1:N и OrderProduct to ProductVariant 1:1   -  person ayk    schedule 27.09.2013


Отговори (1)


Фактът, че получавате ObjectDisposedException извън контекста, показва, че Entity Framework се опитва да зареди обекта, към който ProductVariant.OrderProduct се отнася, чрез мързеливо зареждане от базата данни.

Сега, това не означава непременно - и това твърдение звучи странно - че ProductVariant.OrderProduct вече не е заредено и попълнено с правилния обект. Вероятно е така, защото това е просто обратното свойство на OrderProduct.ProductVariant, което сте заредили чрез нетърпеливо зареждане. За релации "един към един" и "един към много" EF автоматично ще попълни свойствата за обратна навигация, когато се зареди свойство за навигация ("Коригиране на връзката").

Въпреки че свойството за обратна навигация е попълнено, то не е непременно маркирано като заредено, което е флаг, поддържан от контекста за всяко свойство за навигация, който казва на EF дали дадено свойство за навигация трябва да бъде заредено от базата данни чрез отложено зареждане когато имате достъп до него във вашия код.

За връзка "един към много" например лесно се вижда, че EF не трябва да маркира навигационно свойство като заредено, когато се попълни поради коригиране на връзката. Например: Ако заредите поръчка, включително нейния клиентски номер - context.Orders.Include("Customer").Single... - колекцията Orders в нетърпеливо заредения клиент ще съдържа тази заредена поръчка (поради коригиране на връзката). Но тази единична поръчка най-вероятно не е единствената поръчка, която този клиент има (или поне EF не може да знае дали това е единствената поръчка или има още в базата данни). Ако получите достъп до колекцията Customer.Orders, обикновено очаквате, че не само тази единична поръчка ще бъде върната, но и всички поръчки на клиента - с други думи, вие очаквате да се случи заявка за отложено зареждане, която зарежда останалите поръчки на клиента от базата данни.

Сега, този аргумент не е наистина убедителен за връзка едно към едно, защото за такава връзка е ясно, че не може да има повече от един свързан обект в базата данни. И така, защо EF ще иска да изпълни заявка за отложено зареждане, ако този единствен свързан обект вече е зареден?

Не знам защо EF все още се опитва да зареди свойството за обратна навигация за връзката едно към едно, но вероятно просто не прави разлика между връзката един към много и връзката едно към едно в това отношение . Може би EF следва общото правило, че ако основната страна на връзката е попълнена от корекция на връзката, тя не е маркирана като заредена и мързеливото зареждане ще се случи във всеки случай, когато получите достъп до нея. (Наистина не мога да видя от вашия кодов фрагмент дали OrderProduct или ProductVariant е главният, това е само предположение.)

Както и да е, във вашата ситуация бих деактивирал мързеливото зареждане или дори създаването на прокси (което включва деактивиране на мързеливото зареждане), защото използвате Include вътре в блок using и мързеливото зареждане няма полза тук. Изключението, което имате, трябва да изчезне тогава:

using (var context = new MyContext())
{
    context.Configuration.ProxyCreationEnabled = false;

    var orders = context.Order.Include("OrderProduct")
                              .Include("OrderProduct.ProductVariant")
                              .Where(some query)
                              .ToList();
}
person Slauma    schedule 27.09.2013