2013-01-17 8 views
8

Mam projekt Entity Framework zawierający 5 oddzielnych tabel. Kiedy wyszukuję dane z tych tabel i używam .Include(), generowane przez nie zapytanie jest bardzo wolne i przekracza limit czasu.Zmieniam moje zapytanie EF linq do procedury przechowywanej. Czy istnieje prosty sposób na skonfigurowanie złożonych mapowań?

Przenieśliłem zapytanie do procedury przechowywanej, a teraz szukam sposobu na wysłanie zapytania do tej procedury przechowywanej i łatwo odwzorowuję dane, które zwraca do istniejących klas danych.

Mój oryginalny LINQ kwerendy do EF DataContext wyglądał następująco:

var data = (from a in context.A 
        .Include("B") 
        .Include("C") 
        .Include("D") 
        .Include("E") 
      where a.Id == someValue 
      select a); 

ona zwrócić obiekt danych Entity że przypominało to:

class A 
{ 
    int Id; 
    string otherProperties; 

    List<B> B; 
    List<C> C; 
    List<D> D; 
    List<E> E; 
} 

Kwerenda że EF generowane do uruchomienia na serwerze SQL zwrócony zestaw wyników, który wygląda mniej więcej tak:

 
C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 
---------------------------------------------------------- 
A1 A2 B1 B2   
A1 A2    C1 C2 
A1 A2    C1 C2 
A1 A2    C1 C2 
A1 A2       D1 D2 
A1 A2       D1 D2 
A1 A2       D1 D2 
A1 A2          E1 E2 
A1 A2          E1 E2 

(Zakłada Nagrywanie 1 B, 3 C, 3 D i 2 E.

Powtórzyłem to zapytanie w procedurze przechowywanej i zredukowałem jego środowisko wykonawcze praktycznie do zera, jednak utknąłem przy próbach wymyślenia sposobu odwzorowania zestawu wyników na moją klasę danych Entity Framework (klasa A od góry).

EF jest w stanie to zrobić, ponieważ robi to gdzieś za kulisami, kiedy używam kwerendy Linq, ale nie jestem pewien, czy to jest coś, do czego miałbym dostęp.

Czy istnieje prosty sposób w Entity Framework do mapowania pojedynczej procedury składowanej (Import funkcji) do wielopoziomowej klasy Entity Framework?

Odpowiedz

2

Znalazłem wpis na blogu, który wyjaśnia, w jaki sposób można to zrobić za pomocą Entity Framework.

http://blogs.infosupport.com/ado-net-entity-framework-advanced-scenarios-working-with-stored-procedures-that-return-multiple-resultsets/

Podsumowując krótko, trzeba napisać procedurę przechowywaną tak zwraca dane w specyficzny sposób, który jest oczekiwany przez Entity Framework, a następnie można użyć trochę EF extensions aby dostosować wykonanie procedury przechowywanej i zmaterializować twój wykres obiektów.

Wygląda na to, że jest on wbudowany w strukturę Entity Framework w przyszłych wersjach (wydaje mi się, że 5.0+), jednak to obejście wygląda na to, że powinno działać w przypadku niższych wersji.

Chociaż w moim przypadku znalazłem, czy właśnie pozbyłem się .Include() w moim zapytaniu Linq i ręcznie wywołałem ładowanie innych właściwości przez odniesienie ich w kodzie przed zwróceniem obiektu, mój problem z wydajnością został naprawiony. Dzieje się tak dlatego, że zamiast budować jedną masową kwerendę między 5 tabelami a niezoptymalizowanymi łączami, uruchamiane jest 5 osobnych zapytań, z których każda pobiera tylko określone dane, których potrzebuje.

1

Gdy optymalizuję EntityFramework, konwertując kosztowne zapytanie do zapisanego procesu, tworzę niestandardową klasę dla wyników, a następnie wykonuję logikę w DbContext, aby przekonwertować moją klasę niestandardową na jednostki.

Więc chcesz stworzyć coś podobnego

public class StoreProcARow 
{ 
public string Name {get;set;} // properties for every column 
} 

a potem w swojej DbContext

public A GetA(int ID) 
{ 
// do stored procedure 
IEnumerable<StoreProcARow> procResult = ... 
// process procResult into A type 

} 
+0

To był mój plan awaryjny, jeśli nie ma łatwej alternatywy wbudowanej w EF. Na każdej klasie jest wiele właściwości, więc będzie dużo pisania w celu zakodowania konwertera. – Rachel

0

Spróbuj AutoMapper.

Można by zrobić coś takiego:

using AutoMapper; 

... 

Mapper.CreateMap<DataModel.B, ReplyObjects.B>; 
Mapper.CreateMap<DataModel.C, ReplyObjects.C>; 
... 
return new A 
{ 
    B = Mapper.Map<DataModel.B, ReplyObjects.B>(varContainingDataForB), 
    C = Mapper.Map<DataModel.C, ReplyObjects.C>(varContainingDataForC) 
    ... 
}; 

Dopóki właściwości twojej ReplyObjects.B dopasowane nazwy i typy na DataModel.B, wszystko będzie mapować się automatycznie!

+0

To prawdopodobnie nie zadziała w moim przypadku, ponieważ mój początkowy zestaw danych zawiera wszystkie dane dla całego wykresu obiektów, a kilka właściwości jest faktycznie nazwanych tak samo (takich jak "Id"). – Rachel

Powiązane problemy