Jestem zaskoczony przez EF 6 .... Mam aplikację internetową, która zachowuje się bardzo źle pod względem wydajności. Analizując, odkryłem, że jeden z winowajców jest moją metodą, która sprawdza, czy kolekcja jest pusta (lub nie) w jednostce EF6.EF6 - nie robię tego, czego się spodziewałem. Any()
Zasadniczo mam:
public partial class BaseEntity
{
public int BaseEntityId { get; set; }
public string Name { get; set; }
// a few more properties, of no concern here....
// a lazily loaded collection of subitems
public virtual ICollection<Subitem> Subitems { get; set; }
}
public partial class Subitem
{
public int SubitemId { get; set; }
public int BaseEntityId { get; set; }
public string Name { get; set; }
// a few more properties, of no concern here....
}
W mojej aplikacji, muszę sprawdzić, czy dana instancja BaseEntity
jest „pusty” - który jest zdefiniowany jako nie mający podelementy. Więc dodałem tę metodę CheckIfEmpty
do drugiego częściowego pliku klasy:
public partial class BaseEntity
{
public bool IsEmpty
{
return !Subitems.Any();
}
}
Teraz pojedynczy BaseEntity
może mieć setki lub tysiące podpunktach - więc chciałem użyć najbardziej skuteczny sposób, by sprawdzić, czy nie było żadnych podelementy . Moja założenie, że nazywając .Any()
na zbiór, który nie został jeszcze załadowany z bazy będzie zasadniczo przekładają się na wezwanie
IF EXISTS(SELECT * FROM dbo.Subitems) ......
SQL - lub coś wzdłuż tych linii - po prostu sprawdzić, czy istnieją jakieś elementy - albo nie. Specjalnie wybrałem .Any()
przez .Count > 0
, ponieważ wiem, że sprawdzanie licznika będzie wymagało wyliczenia całej kolekcji, a zatem jest wysoce nieefektywne, gdy chcę tylko wiedzieć, czy (lub nie) istnieją jakieś elementy.
I nie trzeba znać ile istnieją, ani też nie jestem zainteresowany w szczegółach - wystarczy prosty TAK lub NO do is empty?
pytanie byłoby wystarczające.
Ku mojemu wielkiemu zdumieniu (i oszołomieniu) okazuje się, że EF6 zmienia to proste połączenie .Any()
w instrukcję SELECT
, która ładuje całą kolekcję ! - to zdecydowanie NIE czego się spodziewali ......
Więc jest jakiś prosty sposób, aby po prostu sprawdzić jeśli nie-jeszcze-załadowany kolekcja ma żadnych wartości - lub nie - BEZ ładowanie całej kolekcji z bazy danych?
Wywołanie 'Subitems' ładunki wszystkie elementy jeszcze przed' . Any został osiągnięty, w ten sposób zaimplementowano leniwy ładowanie. Przy pierwszym dostępie do 'Subitems' jest on ładowany. Staram się nigdy nie używać leniwego ładowania, ale komplikuje to mój kod: staram się zamknąć kontekst tak szybko, jak to możliwe, i otworzyć kolejny inny dla 'db.Subitem.Any (si => si. BaseEntityId == .. .) ' – Kobi
' SubItems' to 'ICollection'. Może działać tak, jak się spodziewasz, jeśli jest to 'IQueryable' (nie jestem pewien, i nie wiem, czy leniwy ładowanie może działać z' IQueryable') –
Korzystając z podejrzanego trybu ładowania i wysyłając zapytanie do DbSet, Uzyskaj to, czego potrzebujesz: context.Set().Każdy(); przekłada się na: SELECT SPRAWY gdy jest ( SELECT 1 OD [TEntity] CO [M]), następnie wylewa się (1 CO BIT) else węglowej (0 jako bit) END –
alessalessio