Siemanko.
Od dawna nic nie piszę, ale postanowiłem to zmienić i co więcej, oprócz pisania planuje troszkę publicznie pokodować i pushować na github’a.
Często rozmyślam nad problemami pojawiającymi się podczas codziennej pracy z różnymi technologiami i równie często tworze w domu nowe solucje w Visual Studio tylko po to aby sprawdzić pomysły na rozwiązania wcześniej wspomnianych problemów. Ostatnio zadałem sobie pytanie czemu by tego nie wrzucać do sieci i w dodatku mieć jakiś temat na post na tym moim nieszczęsnym blogu? 😉 Dlatego od teraz każdy poryty kod bedzie lądował na githubie, a tu z kolei kilka zdań na temat przyczyn jego powstania 🙂
EF Core nie wspiera widoków SQL
Ostatnio w robocie piszę funkcjonalności związane z raportowaniem ilościowym danych wg wielu kryteriów. W projekcie używamy tylko i wyłącznie Microsoft’owego ORMa w wersji Core (gdyż aplikacja jest w Asp.Net Core). Przy tego typo raportach, które mam okazję implementować EF wypada bardzo słabo czasowo ponieważ where’owanie czy group’owanie po kolumnie w czwartej z kolei join’owanej tabeli powoduje, że ef musi wykonać całe query jeszcze przed uwzględnieniem where’a aby mieć zmapowane dane z tej czwartej join’owanej tabelki żeby w końcy wykonać na tych danych where’a. 🙂 Wiem, nieźle zakręciłem, ale chodzi finalnie o to że mimo iż w wyniku dostaniesz 10 rekordów to EF może wcześniej wykonać query na 10000 tys. rekordów żeby mieć dostęp do danych z którejś z kolei zjoinowanej tabelki, które zostały uwzględnione w klauzuli where :). W celu poprawy wydajności pomyślałem żeby stworzyć widok SQL, w którym będę miał wszystkie potrzebne kolumny. Niestety EF Core nie wspiera (jeszcze) widoków w przeciwieństwie do EF 6.
Workaround
Wymyśliłem sobie kontekst sklepu. W sklepie jest klilka produktów, które sa pogrupowane w kategorich. Produkt może byc w wielu kategoriach i kategoria może mieć wiele produktów więc mamy tabelkę łączącą relacje wiele do wielu. Oprócz tego produkty sa powiązane relacją jeden do wielu z tabelka zdjęć. Zdjęcie może być tylko dla jednego produktu, a produkt może mieć wiele zdjęć. Chcę pobrać listę kategorii z ich podstawowymi informacjami wraz z jednym losowym produktem i jego zdjęciem oznaczonym jako IsMinPhoto (czyli miniaturka).
Ef Core umożliwia wykonania selecta z czystego SQL poprzez metodkę FromSql(). Metodka ta może zostać wywołana na propercie DbSet<> obiektu DbContext. Utworzyłem sobie zatem model zawierający kolumny, które będą w widoku. Po utworzeniu bazy zostanie utworzona taka tabela jednakże będzie ona zawsze pusta. Tabela wymaga posiadania klucza Id na podstawie, którego EF mapuje rekordy z bazy danych na obiekty jednakże widok nie posiada swojego Id, gdyż jest to tylko zestaw kolumn z innych tabel. Jako klucz dla modelu odwzorującego widok dodałem pole typu string. Bardzo ważne jest aby odpowiednik tego pola znalazł sie także w widoku z tabelki, której rekordy się nie powtarzają w żadnej relacji (w moim przypadku tabelka Photo). Następnie utworzyłem widok SQL w SQL Managment Studio z użyciem designera.

Model EF

Widok SQL w SQL Mangment Studio
Czytanie z widoku

Podsumowanie
Zrobiłem porównanie czasowe z normalnym zapytaniem zrobionym przez Linq na ORMie i przy łącznie raptem kilkunastu rekordach we wszystkich tabelach wyciąganie danych z widoku jest 3krotnie szybsze i w Sql Profilerze widać tylko jedno zapytanie natomiast gdy robił to ORM zapytań w tym przypadku było 3.
Kodzik z testami do uruchomienia znajduje się na githubie.
Pjona!