Entity Framework Method syntax vs Query syntax

Method syntax vs Query syntax
Method syntax
55%
55% [6]
Query syntax
45%
45% [5]
Odpowiedz Nowy wątek
2017-05-26 11:39
0

Cześć,

Jak wiadomo kiedy jest wybór to jest dobrze... Ale kiedy jest za duży wybór to może być różnie. W przypadku zapytań Entity Framework mamy dwa rodzaje składni. I powiem Wam, że czasami query syntax wygląda pięknie... ale czasami jak się na to patrzy i przepisze na method zaczyna wyglądać dużo lepiej. Relacja zachodzi naturalnie również w drugą stronę. Można też mieszać ze sobą style.

No i tutaj rodzi się pytanie: co preferujecie? Ze swojej strony powiem, że zaczynam doceniać query syntax, szczególnie w przypadku kiedy już naprawdę muszę zrobić joina jawnie.

Głosować! ;)

edytowany 2x, ostatnio: grzesiek51114, 2017-05-26 11:40

Pozostało 580 znaków

2017-05-26 14:27
1

Query. Za te potworki z method + lambda powinno być wieszanie za jaja. Np tu: https://stackoverflow.com/que[...]ode-add-and-statement-to-join

Za to chyba kastracja się należy. Konia z rzędem kto obejmie rozumem to zapytanie, bez pomocy ide.

edytowany 1x, ostatnio: Tokarz_, 2017-05-26 14:28

Pozostało 580 znaków

2017-05-26 14:32
0

@Tokarz_: No właśnie dlatego też wybrałem query. Jednak, przynajmniej dla mnie, jest to takie trochę bardziej czytelne podejście. Co to method to dokładnie o taki przykład mi chodziło jak pokazałeś. Wypisz wymaluj. W przypadku query nawet nie trzeba joina pisać tylko przykładowo:

from c in db.Companies
from p in c.Persons.DefaultIfEmpty()

I samoczynnie leci LEFT JOIN. Niestety w EF nie da się wielokroć stosować podejścia: do not join, navigate, ponieważ, w przypadku kiedy w encji mamy kolekcję po której chcemy się joinować, a nie pojedynczy obiekt, zamiast zwykłego joina EF postanowi wstawić nam podzapywanie i wydajność leci na łeb na szyję. Czasami trzeba zrobić joina jawnie, a przypadku składni method to jakaś masakra ;)

ORM nie po to został stworzony żeby było trudniej.

PS: kod, który przytoczyłem jako przykład też pewnie dałoby się uzyskać za pomocą method ale... nawiasy i lambdy...

edytowany 7x, ostatnio: grzesiek51114, 2017-05-26 14:58

Pozostało 580 znaków

2017-05-26 14:39
1

Jak dla mnie, method + lambda i owszem, do prostego filtrowania listy np, typu:

lista.First(x=>x.id == 1) zwróci element, gdzie id jest równe 1. Ale jeśli ktoś pisze takie zapytania jak podałem wcześniej, to chyba tylko po to żeby robić innym na złość.

Pozostało 580 znaków

2017-05-29 02:27
4

Dla imperatywnego, obiektowego języka jakim jest C# dużo bardziej naturalne jest łańcuchowe wywoływanie metod. Dodatkowe słowa kluczowe tworzące jakiś pseudo DSL udający SQL to tylko śmietnik w języku. Języki programowania powinny być ekspresywne. Mało słów kluczowych i konstrukcji, mało pisania, duże efekty. Wprowadzanie kilkunastu słów kluczowych do języka jest totalnym zaprzeczeniem ekspresywności.
Wywoływanie metod wygląda też w większości przypadków lepiej - query syntax jest zwięźlejsze tylko przy tych nieszczęsnych joinach i w przypadku deklarowania wewnętrznych zmiennych w zapytaniach (let). Tylko, że jeśli trzeba pisać joiny mimo korzystania z ORMa, to chyba coś nie tak jest z mapowaniami.

Poza tym, nie istnieje żaden racjonalny argument za korzystaniem z EF. Jeśli potrzebny jest pełny ORM, to są lepsze rozwiązania. Jeśli chcemy korzystać z istniejącej bazy albo piszemy prostą aplikację, to lepiej sprawdzi się Dapper albo inny mikroORM. Jeśli zaś zależy nam na wydajności, to też lepiej sprawdzi się mikroORM.


"HUMAN BEINGS MAKE LIFE SO INTERESTING. DO YOU KNOW, THAT IN A UNIVERSE SO FULL OF WONDERS, THEY HAVE MANAGED TO INVENT BOREDOM."
edytowany 1x, ostatnio: somekind, 2017-05-29 02:27

Pozostało 580 znaków

2017-05-29 10:17
3

Tylko, że jeśli trzeba pisać joiny mimo korzystania z ORMa, to chyba coś nie tak jest z mapowaniami.

Pójdę z tym nawet dalej - po stronie kodu w ogóle nie powinno być skomplikowanych zapytań. Jeśli robisz jakieś joiny czy inne kosmosy, to IMHO powinieneś stworzyć funkcję lub widok po stronie bazy danych.

Pozostało 580 znaków

2017-05-29 10:25
1

@aurel: też tak uważam. Nie mówiąc już o tym jak "piękne" zapytania czasami potrafi wygenerować ORM. Każdorazowe sprawdzanie tego jakie zapytanie poszło do bazy przeczy idei ORM'a. Mam mieć pewność, że poszło dobre zapytanie i kropka. Widok gwarantuje spełnienie tego warunku.

Jak czasami widzę ile podzapytań jest generowanych przez ORM, zamiast zrobić zwykłego joina, to zaczynam wątpić w takie zabawki.

edytowany 2x, ostatnio: grzesiek51114, 2017-05-29 10:26

Pozostało 580 znaków

2017-05-29 10:46
ŁF
0

@aurel - w ten sposób część logiki biznesowej ląduje po stronie bazy danych. I masz ją wtedy w dwóch miejscach, co już z założenia jest słabe. Kod po stronie bazy danych jest trudniejszy w utrzymaniu, bo jest mniej przejrzysty i cieżej pisze się do niego testy. Zgadzam się, że w pewnych przypadkach nie da się zrobić inaczej, niż przenieść zapytanie do bazy danych, ale są to przypadki wyjątkowe.

@grzesiek51114 - nieważne jak wygląda kod sql, który jest wygenerowany i w związku w tym nie musi go czytać inny programista w celu zrozumienia danego fragmentu logiki. Ważne jest, jak szybko ten kod się wykona. Zapytania idące do bazy danych ZAWSZE powinny być sprawdzone pod kątem wydajności. To, że Tobie wydaje się, że wykona się szybko zweryfikuje tylko rzeczywistość, czyli lektura planu zapytania wykonanego na kopii produkcyjnych danych. Jeśli tworzysz view, to jego użycie również powinno być sprawdzone pod kątem wydajności, bo mogłeś np. pomylić kolejność pól w where i optymalizator zignoruje indeks, albo użyjesz view niezgodnie z przeznaczeniem i w zapytaniu znajdzie się kilka table/index scanów dużych tabel. Sam nie zauważysz różnicy pomiędzy 1ms a 100ms czasu wykonania zapytania, a produkcja obciążona wieloma użytkownikami klęknie albo zacznie płonąć. Twoje zaoszczędzone 15 minut może zabrać kilka godzin pracy administratorom i innym programistom.


Pozostało 580 znaków

2017-05-29 11:28
0

Czyli co, znów odwieczny spór? Jedni chcą przenosić logikę do bazy danych, a inni twierdzą że to złe

Pozostało 580 znaków

2017-05-29 11:47
0

@aurel - w ten sposób część logiki biznesowej ląduje po stronie bazy danych.

Musielibyśmy chyba porozmawiać o konkretnych przykładach, bo ja nie widzę tutaj logiki biznesowej. Natomiast tak z doświadczenia, im więcej sqla w twoim kodzie, tym więcej krytycznych błędów wynikających z tego, że ktoś coś zmienił w bazie danych i nie powiedział. Podczas gdy kiedy ten kod jest po stronie bazy danych, to jest jakby nie mój problem.

Np. gdy korzystam z jakiegoś restowego API, i ktoś zrobi zmiany w tym API, to te zmiany nie mają prawa wpłynąć na działanie istniejących klientów. Jak masz breaking changes to podbijasz wersję, żeby nic nikomu nie popsuć. Tak samo uważam, że osoba robiąca zmiany w bazie danych powinna je robić tak, żeby klienci bazy w ogóle tego nie zauważyli. Skomplikowane, wielopoziomowe joiny w kodzie klienta praktycznie to uniemożliwiają. IMHO sposobem na to jest właśnie dodanie pewnej warstwy logiki po stronie bazy.

I masz ją wtedy w dwóch miejscach, co już z założenia jest słabe.

To nie jest z założenia słabe, tak jak powtórzenie walidacji na backendzie mimo walidacji na froncie nie jest słabe. Po prostu czasem lepiej jest zrobić coś, co wydawałoby się złym pomysłem w innym wypadku. Jeśli mam do wyboru skomplikowane joiny w kodzie, albo zrobienie widoku i proste jego wołanie, to raczej wybiorę to drugie.

Zapytania idące do bazy danych ZAWSZE powinny być sprawdzone pod kątem wydajności.

I dlatego wolę, gdy jakieś bajery na bazie robi bazodanowiec, bo się na tym zna. Ja nie jestem specjalistą od bazy i nigdy nie będę. Ja w ogóle nie chcę wiedzieć gdzie są indeksy, a gdzie nie ma - ja chcę tylko moje dane.

edytowany 2x, ostatnio: aurel, 2017-05-29 11:51

Pozostało 580 znaków

2017-05-29 13:04
ŁF
1
aurel napisał(a):

Musielibyśmy chyba porozmawiać o konkretnych przykładach, bo ja nie widzę tutaj logiki biznesowej. Natomiast tak z doświadczenia, im więcej sqla w twoim kodzie, tym więcej krytycznych błędów wynikających z tego, że ktoś coś zmienił w bazie danych i nie powiedział.

Nadal pracujesz w WK, że ktoś coś zmienia w bazie danych i nie mówi o tym? ;P We w miarę dobrze zaprojektowanej i napisanej aplikacji każda zmiana w strukturze bazy jest odwzorowywana w zmianie modelu ORM, a logika jest przykryta testami. Jeśli ktoś coś spieprzy, to zwykle albo wywali się kompilacja, albo któryś z testów jednostkowych/integracyjnych.
Im więcej sql w bazie danych, tym mniej "sql" po stronie języka programowania wyższego poziomu. Zatem więcej spaghetti-kodu, bo sql ciężko dzieli się na klasy i metody. Za tem mniej testów lub ich brak, bo sql po stronie bazy danych trudniej się testuje. Sql jest jak assembler, generalnie nie nadaje się do implementacji dużej ilości logiki (z pewnymi wyjatkami).

aurel napisał(a):

Podczas gdy kiedy ten kod jest po stronie bazy danych, to jest jakby nie mój problem.

Ciekawe podejście. Twierdzisz, że lepiej, żeby więcej kodu bylo w tej części systemu, do której się nie dotykasz, bo będziesz mieć mniej pracy. Ale bazodanowiec przecież powie cos dokładnie przeciwnego, będzie chciał mniej kodu w sql, wiecej w C#. Które z was będzie miało rację? Mam wrażenie, że kryterium "to nie będzie mój problem" nie powinno być wyznacznikiem pisania kodu. Kod ma efektywnie spełniać swoje zadanie, a do tego być czytelny i łatwy do testowania. Nie ma tu miejsca na "to nie będzie mój problem", bo za kilka lat okaże się, że utrzymanie tej aplikacji kosztuje tak dużo, że projekt zostanie zarzucony (masz to opisane na początku książki Clean Code). A Ty rok wcześniej zmienisz miejsce pracy i faktycznie tamta aplikacja już nie będzie Twoim problemem. Można i tak ;-)

aurel napisał(a):

Np. gdy korzystam z jakiegoś restowego API, i ktoś zrobi zmiany w tym API, to te zmiany nie mają prawa wpłynąć na działanie istniejących klientów. Jak masz breaking changes to podbijasz wersję, żeby nic nikomu nie popsuć. Tak samo uważam, że osoba robiąca zmiany w bazie danych powinna je robić tak, żeby klienci bazy w ogóle tego nie zauważyli. Skomplikowane, wielopoziomowe joiny w kodzie klienta praktycznie to uniemożliwiają. IMHO sposobem na to jest właśnie dodanie pewnej warstwy logiki po stronie bazy.

Jeśli robisz breaking change w bazie danych, to trochę ciężko będzie nie wpłynąć na istniejace API, kod może mieć wersje, baza danych już nie za bardzo.
Piszesz, że "skomplikowane joiny" w kodzie klienta uniemożliwiają wprowadzenie zmian w taki sposób, żeby klienci bazy tego nie zauważyli. Nie zgadzam sie z Tobą, bo problem jest zupełnie w innym miejscu. Jak sama napisałaś, pomiędzy klientem a bazą masz API, które w razie większych zmian w bazie zwykle zapewni wsteczną kompatybilność. Cienki klient, jakim jest przeglądarka internetowa, nie potrzebuje takiej kompatybilności w ogóle. Dodanie warstwy abstrakcji po stronie danych w postaci np. view albo sp nie zagwarantuje uniknięcia wymuszenia zmian w klientach, spowoduje za to dodanie jeszcze jednej warstwy, którą trzeba utrzymywać - dokumentować zmiany, przykrywać te zmiany testami, wdrażać nowych programistów w działanie. Po co nowa warstwa, kiedy jej zadanie może spełnić warstwa już istniejąca?

BTW "skomplikowane joiny", co to takiego? Sql ma setki miejsc, gdzie można utworzyć potworki, ale joiny moim zdaniem do nich nie należą, są moim zdaniem fajnym sposobem na uproszczenie i pogrupowanie listy warunków z klauzuli where.


edytowany 1x, ostatnio: ŁF, 2017-05-29 13:22

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0