Entity Framework Core - właściwość modelu (tylko do odczytu) bez kolumny w tabeli

0

Witam.
Mam pewien (głupi) problem. Otóż tabela CustomerDevice nie posiada kolumny ServiceDate. Ta właściwość w modelu jest mi potrzebna tylko w jednym przypadku w aplikacji i jest tylko do "wyświetlania danych", żadnych insertów z tym nie mam zamiaru robić. Jest to niestandardowa "kolumna", wyliczana w całym select query z innej tabeli (tak mi było "łatwiej). Ustawiając atrybut [NotMapped] ta wartość nie jest wczytywana "z bazy". Bez [NotMapped] dostaję wyjątek, że kolumna w bazie nie istnieje... Jakieś rozwiązanie?

1

To zrób sobie druga klasę z tą właściwością i twórz obiekty tej klasy.

1

A uogólniając - trzymaj się SRP i oddziel ViewModel od PersistenceModelu.

0

Nikt nigdy nie przewidział tego, że chce mieć jakąś właściwość w klasie, która nie jest kolumną w tabeli? Nie prościej by było stworzyć atrybut, który by decydował jak dana właściwość "ma się zachować"? Jaki jest sens takiego modelu skoro i tak muszę stworzyć osobną klasę (czyli kopie tego co już mam) tylko dlatego, że mój dbContext nie ogarnia jednej propertki, która nie jest kolumną w bazie :D Takie przypadki są tak bardzo rzadkie, czy to znowu zmierzanie w kierunku "dobrych praktyk" i, że pozwolę sobie zacytować mistrza, kultu cargo...?

0

Nie wiem jak jest w Core. W EF 6 NotMapped działa poprawnie. Działa też Ignore z FluentAPI. Nie ma Ignore w EF Core?

0

Skoro wyliczasz coś i ma nie być kolumną to https://entityframeworkcore.com/querying-data-projection

0

@jacek.placek:
[NotMapped] działa, ale w dwie strony. A ja chce żeby ignorował tylko na insert, a przy select pobierał dane o ile są pobierane. W innym przypadku niech wartość jest jaka sobie chce bo wtedy jej nie potrzebuje. Marzy mi się coś jak:

[NotMapped] - ignoruje w dwie strony
[NotMappedForInsert] - ignoruje na insert
[NotMappedForSelect] - ignoruje na select

@boska_cebula
Co w przypadku gdy wyciągasz dane za pomocą FromSqlRaw()? Nie masz danych w tej właściwości bo jest oznaczone jako [NotMapped]. Kolumny w bazie też nie masz, ponieważ wartość dla tej kolumny jest pobierana z innej tabeli. W moim przypadku (DateTime) dostanę '0001-01-01'

1

Jaki jest sens takiego modelu skoro i tak muszę stworzyć osobną klasę (czyli kopie tego co już mam) tylko dlatego(...)

Podział odpowiedzialności, podział na warstwy itp.

0

@WeiXiao Nope ;-)

@Aventus Model za co jest odpowiedzialny? Za reprezentację danych. Skoro potrzebuje tam daty, która nie musi być kolumną to dlaczego mam tego nie zrobić?


Może napiszę co próbuje uzyskać. Może źle do tego podchodzę. Projekt to aplikacja webowa do zarządzania serwisem urządzeń fiskalnych. Prosty, podstawowy system, tylko do celów wewnętrznych. Co 2 lata robi się przegląd techniczny kasy/drukarki fiskalnej. Na głównej stronie wyświetlam urządzenia "Do przeglądu", czyli te, których przegląd został zrobiony 2 lata temu i trzeba go zrobić "teraz". Każde urządzenie jest powiązane z tabelą "ZdarzeniaUrządzenia", w którym są notowane przeglądy, fiskalizację, serwisy itp itd.

Zapytaniem SQL (lambda i linq mnie pokonało) wyciągam urządzenia ("join" do zdarzeń), których Max(DataZdarzenia) jest w przedziale od - do i właśnie ta Max(DataZdarzenia) jest przypisana do właściwości ServiceDate. Mam nadzieje, że krótki opis jest w miarę zrozumiały.

3

Model za co jest odpowiedzialny? Za reprezentację danych. Skoro potrzebuje tam daty, która nie musi być kolumną to dlaczego mam tego nie zrobić?

Rzecz w tym, że właśnie po to stosuje się podział odpowiedzialności i warstw aby- między innymi- zapobiec problemom takim jak ten z którym masz do czynienia. Model (domyślam się że modelem nazywasz encję, ja bym tego tak nie nazwał) w przypadku EF- i większości ORMów- jest odpowiedzialny za reprezentację danych, masz rację. Pomijasz jednak ważny szczegół, a mianowicie że chodzi o reprezentację danych 1:1. Twój ServiceDate jest właściwościową która musi zostać zbudowana dynamicznie, a więc już samo to wskazuje że masz kandydata na model widoku. Możesz go zbudować na kilka sposobów:

  • Załadować w pamięci dane które potrzebujesz z różnych źródeł i na ich podstawie zbudować model widoku
  • Zbudować model widoku za pomocą zapytania SQL (lub stored procedure) i zmapować wynik na model widoku
  • Budować dedykowany materialized view w bazie danych, zakładając że ServiceDate może być obliczone wcześniej niż na etapie wyciągania z bazy danych

W każdym przypadku jednak potrzebujesz modelu widoku, oddzielnie od Twojego "modelu" (encji).

0
AdamWox napisał(a):

Jaki jest sens takiego modelu skoro i tak muszę stworzyć osobną klasę (czyli kopie tego co już mam) tylko dlatego, że mój dbContext nie ogarnia jednej propertki, która nie jest kolumną w bazie :D Takie przypadki są tak bardzo rzadkie, czy to znowu zmierzanie w kierunku "dobrych praktyk" i, że pozwolę sobie zacytować mistrza, kultu cargo...?

To są bardzo częste przypadki. Kultem cargo jest pchanie encji na twarz. Jak widzisz, powoduje to komplikacje i to już w miarę wcześnie.

AdamWox napisał(a):

Model za co jest odpowiedzialny? Za reprezentację danych. Skoro potrzebuje tam daty, która nie musi być kolumną to dlaczego mam tego nie zrobić?

Model składowania to nie model widoku ani nie model domeny. Nie da się tworzyć nietrywialnych aplikacji w tylko jednej warstwie.

A jeśli oczekujesz, żeby ORM zapewniał różne bajery, to użyj jakiegoś dojrzałego rozwiązania, a nie czwartej inkrementacji tej samej microsoftowej kupy.

0

@Aventus:
Czy tylko ja widzę w tym "głupi" problem? Dlaczego te wszystkie oddzielania warstw mają mieć w pływ na jedną właściwość? Dlaczego mam się pocić, tworzyć pierdyliard klas tylko dlatego, żeby "dobrze" zaimplementować jedną właściwość, która nie ma być kolumną w tabeli i powtarzać sobie w głowie SRP, SRP, SRP? Wracamy do punktu wyjścia, czyli do mojego posta na temat tych głupot...

@somekind
skoro to są bardzo częste przypadki to dlaczego ktoś nie wpadł na to, żeby zrobić tak jak pisałem wyżej? Już tych "dojrzałych ORMów" się nie czepiam. Aplikacja jest mała, dla 4 osób max i aż tak drążyć tematu nie mam zamiaru, który ORM jest lepszy.

Uważam, że posuwa się to za daleko w kwestii projektowania aplikacji webowych. Stworzyłem sobie tą kolumnę w bazie jako nullable i niech sobie tam jest... Tragedia

0

@AdamWox:
Nie zrozum mnie źle, ale nie wiele wyniosłeś z wątku który sam założyłeś - .NET Core WebAPI - serwisy, repozytoria, automapery, DTO, Dapper, EF

Odpowiadając na Twoje pytanie czy jest możliwość pominięcia jednego propertisa w modelu, który chcesz pobierać z bazy - nie wiem, sam sprawdziłeś, że [NotMapped] nie działa tak jak oczekujesz, koledzy z forum rzucili kilka różnych pomysłów (moim skromnym zdaniem dobrych - m.in materialized view albo skorzystanie z FluentApi), które uważasz za "wyciąganie armaty na muchę". Rozumiem Twoją motywację i chęć stosowania najprostszych rozwiązań no, ale nie zawsze się da albo nie zawsze jest to wskazane (dlaczego? patrz do tematu który sam założyłeś).

Pozdrawiam

0

@Krzysztof Pe:
Tamten temat, który założyłem był poglądowy. Wyciągnąłem z niego to co uważałem za stosowne i potrzebne. Chyba mam do tego prawo? To co chłopaki proponują tutaj jest ok, ja zwyczajnie kontynuuje dyskusję, aby dowiedzieć się jak najwięcej i ewentualnie przekazać swój punkt widzenia i zapytać dlaczego dla takiej błahostki trzeba "stawać na głowie", instalować kolejne biblioteki, tworzyć kolejne klasy, ponieważ projektant (ja) zażyczył sobie jedną, głupią, ale ważną właściwość w klasie, która nie ma być kolumną w tabeli. Tak jak tam pisałem wiele razy, jestem typem buntownika, który często nie zgadza się na coś co nie ma sensu. Mam wybór:

  1. SRP, druga klasa z datą, DTO, materialized view, fluentapi
  2. Kolumna ServiceDate (allow null) w tabeli - dla świętego spokoju

Wchodzę w świat ASP .NET Core. Nie znam wszystkiego. Jak zwykle liczyłem na banalne rozwiązanie jakimś atrybutem, ustawieniem, a tu jednak punkt 1. jest górą, dlatego wybrałem punkt 2. i śpię spokojnie ;-)

Również pozdrawiam

2

Nie chciałbym i mam nadzieję że nie będę z tobą nigdy pracował skoro świadomie i z premedytacją robisz taki syf w kodzie i bazie.

1

@AdamWox: jeśli w Twojej aplikacji jest możliwość i sens trzymania kolumny ServiceDate w tabeli to dla czego właśnie tego po prostu nie zrobić? Lub tak jak już wspomniałem zbudować sobie model za pomocą zapytania SQL, I możesz tam wtedy obliczać dynamicznie co tylko chcesz.

Co do reszty Twojej wypowiedzi to myślę że problem leży w tym że oczekujesz od ORMa czego do czego nie jest stworzony, bo jego głównym celem jest ułatwienie zarządzania encjami i wyeliminowanie potrzeby pisania własnego SQL i infrastruktury do wyciągania z bazy, śledzenia stanu i zapisywania rekordów. Ujmując to inaczej, pijesz herbatę i narzekasz że nie smakuje jak kawa.

1

Porównanie genialne :-) i prawdopodobnie masz rację. Wyszedłem z założenia, że skoro jest atrybut [NotMapped] to jest też jakiś atrybut, który pozwala na zdecydowanie czy ma być na select, czy na insert. Nikt mnie nie pilnuje jak buduję bazę, jakiego kodu używam i mnie się to podoba. Sam później, jak nabieram doświadczenia, wstydzę się za to co napisałem rok temu. W tym przypadku uważam, że kolumna nikomu krzywdy nie zrobi, ani też nie zwolni pracy aplikacji, a problem rozwiązany zdecydowanie szybciej (jak dla mnie).

PS.
Wrócę do tego posta za rok, aby ze wstydem poczytać, że doradzaliście mi lepiej niż to rozwiązałem ;-)

0
AdamWox napisał(a):

Czy tylko ja widzę w tym "głupi" problem? Dlaczego te wszystkie oddzielania warstw mają mieć w pływ na jedną właściwość? Dlaczego mam się pocić, tworzyć pierdyliard klas tylko dlatego, żeby "dobrze" zaimplementować jedną właściwość, która nie ma być kolumną w tabeli i powtarzać sobie w głowie SRP, SRP, SRP? Wracamy do punktu wyjścia, czyli do mojego posta na temat tych głupot...

To nie chodzi o jedną właściwość, tylko o to, że później problemów pojawi się więcej i zapewne nie tylko z właściwościami.
I nie trzeba wcale pierdyliarda klas, na razie jedna dodatkowa by Ci wystarczyła. Zrobienie tego dobrze zajęłoby mniej czasu niż spędziłeś w tym wątku.

skoro to są bardzo częste przypadki to dlaczego ktoś nie wpadł na to, żeby zrobić tak jak pisałem wyżej?

Ależ wpadł. W takim NHibernate robisz IgnoreProperty i to wszystko. Jak taki efekt osiągnąć w EF 42323 hipster edition nie mam pojęcia, na szczęście nie musiałem jeszcze z tego korzystać.
A najłatwiej chyba byłoby Ci po prostu użyć Dappera.

Aplikacja jest mała, dla 4 osób max i aż tak drążyć tematu nie mam zamiaru, który ORM jest lepszy.

Generalnie masz opcje takie, że albo robisz profesjonalną architekturę, albo używasz narzędzi, które ułatwiają hakowanie. Tymczasem Ty rezygnujesz z jednego i drugiego.

0

@somekind:
Ten pierdyliard klas był ironią, wyolbrzymieniem. Dla tak małego projektu to jest jedna dodatkowa klasa. Dla większych projektów pewnie robi się tego więcej i w tym drugim przypadku pewnie ma to sens, bo wtedy faktycznie łatwo o bałagan i w bazie i w kodzie. Choć w dalszym ciągu uważam, że to jest niepotrzebne powielanie klas. Jestem na 99% pewny, że jeszcze ładnych parę lat w tej firmie będę programował sam, stąd takie "babole" nie robią mi krzywdy. Nikomu tego tłumaczyć nie muszę, a program działa i wszyscy się cieszą. Jak "babol" z czasem będzie mnie dręczył to go poprawię. Szkoda, że poprzez kurczowe trzymanie się pewnych zasad i "jednej właściwości" twierdzisz, że nie robię profesjonalnej architektury, ale cóż... Nie można mieć w życiu wszystkiego ;-)

1

No dobra
Ja przepraszam. Nie wiedziałem, że EF Core jest uposledzony i nie ma SqlQuery takiego jak w EF6.

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