Lucrez acum la un proiect în care folosim ASP.NET MVC și ADO.NET Entity Framework. Fiind primul proiect cu EF, descoperim pas cu pas cum anume se lucrează cu el.
Azi m-am lovit de următoarea problemă. Se dau două tabele în baza de date (Întrebare și Categorie), relaționate 1 – *, o categorie corespunzănd la mai multe întrebări, respectiv entitățile generate cu EF. Acesta fiind un Object – Relational Mapper, în clasa Întrebare generată vom avea o proprietate Categorie de tip Categorie, respectiv una CategorieReference de tip EntityReference<Categorie>, fără să avem una de genul IdCategorie.
La un moment dat selectezi câteva Întrebări din entitățile EF, și dorești să vizualizezi Categoria pentru fiecare Întrebare. Ceva de genul acesta:
ViewData["Categorie"] = intrebareSelectata.Categorie;
Vei observa că acest obiect, Categorie, este null. Motivul e simplu: întrebările selectate au fost încărcate din baza de date fără obiectele care rezultă mergând pe relații. Pentru a avea și obiectul Categorie asociat unei Întrebări încărcate, sunt două variante:
1. Atunci când interogăm setul de Întrebări, folosim o metodă care automat include obiectele relaționate:
Intrebare problemaSelectata = (from intrebare in entities.Intrebare.Include("Categorie") …
1. Altfel, fără metoda Include() de mai sus, folosind proprietatea CategorieReference:
problemaSelectata.CategorieReference.Load();
Din acest moment, Categoria aferentă Întrebării (-lor) este și ea încărcată din baza de date.
[UPDATE]
Mi s-a întâmplat (de fapt colegului meu Stefy) ca în unele situații acest eager loading realizat cu metodele Include() să nu meargă. Este explicat mai bine aici: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=347543 , dar pe scurt relatez și eu. Dacă interogarea este ”mai complexă” (nu știu toate cazurile, ei au acolo un exemplu, eu vă arăt altul imediat), atunci Include() pur și simplu nu face nimic. Problema mea e că nici nu aruncă o excepție …
Iată exemplul nostru:
var query = (from intr in entities.Intrebare.Include("Clase")
join categ in entities.Categorie on intr.Categorie equals categ
where intr.Formulare.IdFormular == idFormConcurs
&& categ.Domeniu.Id == idDomeniu
orderby intr.NrOrdine ascending
select intr).ToList<Intrebare>();
Aici se pare că nu îi place join-ul și acel Include(”Clase”) nu face nimic. Rezolvarea este următoarea:
var query = (from intr in entities.Intrebare.Include("Clase").Include("Categorie")
where intr.Formulare.IdFormular == idFormConcurs
&& intr.Categorie.Domeniu.Id == idDomeniu
orderby intr.NrOrdine ascending
select intr).ToList<Intrebare>();
Cu alte cuvinte, înlocuim join-ul necesar pentru verificarea unei condiții prin includerea obiectului respectiv folosind Include(”Categorie”) și apoi efectuarea verificării pe obiectul intr.Categorie. E destul de logic până la urmă să lucrăm pe obiecte până la capăt, și nu să avem un mix relațional-obiectual în aceeași interogare.