Virtualna właściwość nawigacyjna w Entity

Virtualna właściwość nawigacyjna w Entity
R2
  • Rejestracja:prawie 11 lat
  • Ostatnio:ponad 8 lat
  • Postów:50
0

witam
Mam do was pewne pytanie, otóż przeglądam pewien kurs i zastanawiam się nad pewnym połączeniem dwóch kolumn ze sobą:

Kopiuj
public class Album
    {
        public int AlbumId { get; set; }
        public int GenreId { get; set; }
        public string AlbumTitle { get; set; }
        public string ArtistName { get; set; }
        public DateTime DateAdded { get; set; }
        public string CoverFileName { get; set; }
        public string Description { get; set; }
        public decimal Price { get; set; }
        public bool IsBestseller { get; set; }

        public virtual Genre Genre { get; set; }
        public bool IsHidden { get; set; }
    } 
Kopiuj
public class Genre
    {
        public int GenreId { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public string IconFilename { get; set; }

        public ICollection<Album> Albums { get; set; }
    } 

I moje pytanie: Czemu

Kopiuj
 public ICollection<Album> Albums { get; set; }

jako właściwość nawigacyjna nie jest ona oznaczona jako virtual gdyż autor raz oznacza ją jako virualną raz nie i właśnie nie wiem dlaczego i od czego to zależy?

DibbyDum
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Polska, Kraków
2

Dodanie virtual powoduje:

  • Lazy Loading czyli załadowanie danych z bazy danych dopiero w momencie kiedy są potrzebne, na żądanie.
  • Efektywniejsze śledzenie zmian w entities(bytach?).

Yubby dibby dibby dibby dibby dibby dibby dum..
R2
  • Rejestracja:prawie 11 lat
  • Ostatnio:ponad 8 lat
  • Postów:50
0

czyli zastosowanie

Kopiuj
 virtual 

ma same plusy więc czemu autor kursu pisał raz tak raz tak?

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:2 dni
  • Lokalizacja:Wrocław
2

Bo to nie są same plusy. Tego się używa wtedy, gdy jest potrzebne, a nie wszędzie.


Po dopracowaniu rozwiązania każdy będzie mógł założyć własny drzewiasty wątek.
R2
  • Rejestracja:prawie 11 lat
  • Ostatnio:ponad 8 lat
  • Postów:50
0

a czy możesz mi wyjaśnić te lazy loading no bo "załadowanie danych w momencie kiedy są one potrzebne" - czyli zawsze chyba (najlepiej na jakimś przykładzie jakbys mógł)

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:2 dni
  • Lokalizacja:Wrocław
4

Masz np. obiekt Faktura, która ma właściwość Klient klasy Klient. I teraz:

  1. Jeśli nie będziesz korzystał z lazy loading, to jeśli pobierzesz z kontekstu EF obiekt Faktura, z bazy od razu wczytany zostanie także obiekt Klient.
  2. Jeśli będziesz korzystał z lazy loading, to pobierając Fakturę pobierzesz tylko ją. Ale jeśli gdzieś w kodzie napiszesz np.: string nip = faktura.Klient.Nip, to wówczas dopiero z bazy zostanie doczytany Klient.

Po dopracowaniu rozwiązania każdy będzie mógł założyć własny drzewiasty wątek.
R2
  • Rejestracja:prawie 11 lat
  • Ostatnio:ponad 8 lat
  • Postów:50
0

dzięki wielkie somekind już łapie :) i poza tym nie ma innych różnic ?

unikalna_nazwa
  • Rejestracja:około 14 lat
  • Ostatnio:ponad 9 lat
2

To jest ogromna różnica
W jednym przypadku jeśli chcesz przelecieć po wszystkich fakturach i zrobić coś na kliencie, poleci do bazy tysiące zapytań i ogólnie aplikacji będzie słabo działać
W drugim przypadku jeśli chcesz przelecieć po wszystkich fakturach ale nie robić niczego z klientami to klienci niepotrzebnie się pobrały i być może wydłużyły niepotrzebnie pobieranie listy faktur oraz zwiększyły liczbę przesyłanych danych z bazy


Pół giga extra na dropboxie? Pół giga extra na dropboxie! Tyle wygrać! >>Klik here<<
1
somekind napisał(a):

Masz np. obiekt Faktura, która ma właściwość Klient klasy Klient. I teraz:

  1. Jeśli nie będziesz korzystał z lazy loading, to jeśli pobierzesz z kontekstu EF obiekt Faktura, z bazy od razu wczytany zostanie także obiekt Klient.
  2. Jeśli będziesz korzystał z lazy loading, to pobierając Fakturę pobierzesz tylko ją. Ale jeśli gdzieś w kodzie napiszesz np.: string nip = faktura.Klient.Nip, to wówczas dopiero z bazy zostanie doczytany Klient.

Dodatkowo wydaje mi się, że gdy wywołasz Dispose na obiekcie DbContext (czyli na przykład obiekt typu DbContext zostanie stworzony poprzez blok using) to próba odwołania się do obiektu klient, który jeszcze nie został załadowany skończy się rzuceniem wyjątku. Jeśli się mylę to mnie poprawcie ;)

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:2 dni
  • Lokalizacja:Wrocław
1
Mały Orzeł napisał(a):

Dodatkowo wydaje mi się, że gdy wywołasz Dispose na obiekcie DbContext (czyli na przykład obiekt typu DbContext zostanie stworzony poprzez blok using) to próba odwołania się do obiektu klient, który jeszcze nie został załadowany skończy się rzuceniem wyjątku. Jeśli się mylę to mnie poprawcie ;)

Nie wiem czy tak jest, ale jeśli tak nie jest, to bardzo źle. Na obiektach pobranych z bazy operujemy wewnątrz jednego unit of work, czyli podczas istnienia jednej instancji DbContextu.


Po dopracowaniu rozwiązania każdy będzie mógł założyć własny drzewiasty wątek.
R2
  • Rejestracja:prawie 11 lat
  • Ostatnio:ponad 8 lat
  • Postów:50
0

dzięki wielkie za odpowiedzi rozjaśniło mi to sporo :)
a tak poza tematem znacie jakieś dobre książki do entity?

0
somekind napisał(a):

Na obiektach pobranych z bazy operujemy wewnątrz jednego unit of work, czyli podczas istnienia jednej instancji DbContextu.

łatwo mówić w przypadku aplikacji webowej gdzie w jednym zapytaniu możemy pozmieniać wszystkie dane
ale jak to jest w przypadku aplikacji desktopowej, gdzie w jednym miejscu pobierany encję, dajemy użytkownikowi możliwość przykładowo jej edycji i dopiero po kilkunastu minutach może nastąpić część z zapisem?

Czy musimy przepisywać encje z entity do jakiegoś innego obiektu a potem na podstawie tego obiektu z powrotem w funkcji zapisu szukać znów tego obiektu na bazie na podstawie jakiegoś ID, po czym przepisać z naszego obiektu do edycji do obiektu bazodanowego entity?
W przypadku gdy chcemy dodać możliwość lokalnego tworzenia / usuwania jakichś subelementów, kod może się nieco skomplikować.
Jak to powinno wyglądać?

0

W takich przypadkach korzystasz z jakiegoś wzorca projektowego np. MVP. Pobierasz enację z modelu, następnie przekazujesz ja do widoku (najlepiej wszystkie właściwości encji zbindować z kontrolkami), na akcję widoku reagujesz najpierw walidacją danych, dopiero potem tworzysz nowy DbContext i dodajesz go do niego przy pomocy Attach z flaga ustawioną na "zmodyfikowany" obiekt.

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:2 dni
  • Lokalizacja:Wrocław
1
Wielki Pomidor napisał(a):

łatwo mówić w przypadku aplikacji webowej gdzie w jednym zapytaniu możemy pozmieniać wszystkie dane
ale jak to jest w przypadku aplikacji desktopowej, gdzie w jednym miejscu pobierany encję, dajemy użytkownikowi możliwość przykładowo jej edycji i dopiero po kilkunastu minutach może nastąpić część z zapisem?

Ten problem występuje, gdy masz jednowarstwową aplikację i łamiesz SRP używając tych samych obiektów w GUI i w ORM. To może dobre w malutkich, jednorazowych aplikacjach, ale nie gdy tworzymy coś poważnego.

Czy musimy przepisywać encje z entity do jakiegoś innego obiektu a potem na podstawie tego obiektu z powrotem w funkcji zapisu szukać znów tego obiektu na bazie na podstawie jakiegoś ID, po czym przepisać z naszego obiektu do edycji do obiektu bazodanowego entity?

Nie musimy (nikt nas za to nie zbije przecież ;)), ale to dobre rozwiązanie.

W przypadku gdy chcemy dodać możliwość lokalnego tworzenia / usuwania jakichś subelementów, kod może się nieco skomplikować.
Jak to powinno wyglądać?

Mógłbyś podać konkretny przykład, bo chyba nie rozumiem?

Można szukać różnych obejść, jak np. w poście wyżej, ja bym jednak tworzył aplikacje wielowarstwowo, nie łamał SRP i nie pisał aplikacji w sposób niewydajny.
Operowanie na tych samych modelach przy operowaniu na bazie i w GUI jest słabe, bo:

  1. Ewidentnie łamiemy SRP.
  2. To, co wyświetlamy w GUI często nie ma związku z tym, co jest w bazie. Zazwyczaj nie potrzebujemy wyświetlać użytkownikowi danych z wszystkich kolumn, więc po co je pobierać? Z drugiej strony często w GUI pokazujemy dane z dwóch obiektów (jak w moim przykładzie). Łączenie obiektów w kodzie GUI jest zazwyczaj trudniejsze, i znacznie mniej wydajne niż zrobienie tego na poziomie najbliższym bazy danych.
  3. Obiekt między odczytem a zapisem mógł zostać zmieniony przez innego użytkownika. To też trzeba obsłużyć (np. przez optimistic concurrency). Żeby to zrealizować musimy obiekt z bazy i tak pobrać jeszcze raz przed zapisem.

Odczyt z bazy i zapis do bazy wykonumemy w oddzielnych UoW, a obiekty ORM to nie ViewModele. Nieważne, czy to aplikacja webowa, desktopowa, konsolowa czy jakaś jeszcze inna. Ja wiem, że to duża zaleta desktopowych aplikacji, że możemy trzymać obiekty w pamięci, nie to co w web, ale nie wpadajmy w tę pułapkę!

P.S. Obiekt ORM to nie jest encja tylko persistence model. (Entity Framework ma zjebaną nawet nazwę.)


Po dopracowaniu rozwiązania każdy będzie mógł założyć własny drzewiasty wątek.
DibbyDum
Obiekt ORM to nie jest encja tylko persistence model. Człowiek tyle czasu żył w nieświadomości. :>
0
somekind napisał(a):

Obiekt ORM to nie jest encja tylko persistence model. (Entity Framework ma zjebaną nawet nazwę.)

Moim zdaniem chodzi o encje w sensie "byt" / "obiekt domenowy", nie o polską definicję encji więc nazwa jest w porządku

Czyli używanie obiektów entity frameworka jako modelu w aplikacji Twoim zdaniem łamie zasadę SRP i oznacza architekturę jednowarstwową?
No ale przecież obiekty dla entity framework mogą implementować interfejsy, mogą być partial i nie widzę przeszkód żeby używać ich jako modeli w ViewModelach dla GUI?
Możesz jakoś zaargumentować swoją wypowiedź?

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:2 dni
  • Lokalizacja:Wrocław
0
Wielki Pomidor napisał(a):

Moim zdaniem chodzi o encje w sensie "byt" / "obiekt domenowy", nie o polską definicję encji więc nazwa jest w porządku

No właśnie - "obiekt domenowy". Obiekty z ORMa to nie są obiekty domenowe. One nie modelują domeny tylko strukturę rekordów w bazie.

Czyli używanie obiektów entity frameworka jako modelu w aplikacji Twoim zdaniem łamie zasadę SRP i oznacza architekturę jednowarstwową?

Używanie obiektów EF w GUI łamie SRP (bo obiekt ma dwie odpowiedzialności - definiuje strukturę danych w bazie oraz wygląd UI. I tak, to świadczy o jednowarstwowości, bo w wielowarstwowej aplikacji jest to nieosiągalne.

Możesz jakoś zaargumentować swoją wypowiedź?

Trzy argumenty dałem w poprzednim poście.


Po dopracowaniu rozwiązania każdy będzie mógł założyć własny drzewiasty wątek.
0
somekind napisał(a):

Używanie obiektów EF w GUI łamie SRP (bo obiekt ma dwie odpowiedzialności - definiuje strukturę danych w bazie oraz wygląd UI

Bycie kontenerem dla dwóch oddzielnych obiektów nie oznacza że obiekt ma dwie odpowiedzialności. Dopóki nie ma jakiegoś zachowania to w ogóle nie ma żadnej odpowiedzialności - inaczej byśmy musieli mówić że wbudowane struktury jak DateTime łamią zasadę SRP bo używamy ich we wszystkich warstwach do różnych celów

Poza tym powiedzmy używamy interfejsu IUser mającego pola Name i LastName, definiujemy "encję" User w warstwie entity frameworka (DAL) implementującą ten interfejs - ta klasa User dopiero definiuje pośrednio strukturę danych w bazie (a tak właściwie mówiąc to przy pomocy refleksji struktura bazy danych jest wzorowana na tym obiekcie)
Z drugiej strony mamy ViewModel przyjmujący obiekt typu zgodnego z IUser i służy za proxy między tym obiektem a GUI wprowadzając jednocześnie walidację wpisywanych danych

Nie widzę tu łamania zasady SRP, nie widzę wymuszenia jednej warstwy i nie widzę sensu przepisywania wszystkich potrzebnych propertów z obiektu z entity framework do jakiegoś POCO tylko po to ( ;) ) żeby nie użyć tego samego obiektu - nie ważne czy robimy to ręcznie czy za pomocą mappera - lepiej moim zdaniem te potrzebne nam w modelu biznesowym property wydzielić do interfejsu

0

Coyote mi zepsuł kawał
Miało pisać POTO

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:2 dni
  • Lokalizacja:Wrocław
0
Wielki Pomidor napisał(a):

Bycie kontenerem dla dwóch oddzielnych obiektów nie oznacza że obiekt ma dwie odpowiedzialności.
Dopóki nie ma jakiegoś zachowania to w ogóle nie ma żadnej odpowiedzialności - inaczej byśmy musieli mówić że wbudowane struktury jak DateTime łamią zasadę SRP bo używamy ich we wszystkich warstwach do różnych celów

Dziwna filozofia, zwłaszcza tekst o DateTime.

Obiekt powinien mieć jeden powód do zmiany. Przy Twoim podejściu masz dwa powody: zmianę w sposobie przechowywania danych, albo zmianę w sposobie wyświetlania w GUI. To nie jest SRP.

Poza tym powiedzmy używamy interfejsu IUser mającego pola Name i LastName, definiujemy "encję" User w warstwie entity frameworka (DAL) implementującą ten interfejs - ta klasa User dopiero definiuje pośrednio strukturę danych w bazie (a tak właściwie mówiąc to przy pomocy refleksji struktura bazy danych jest wzorowana na tym obiekcie)
Z drugiej strony mamy ViewModel przyjmujący obiekt typu zgodnego z IUser i służy za proxy między tym obiektem a GUI wprowadzając jednocześnie walidację wpisywanych danych

Czyli ViewModel, który jest de facto tylko walidatorem do obiektu ORMa pod kątem danych wprowadzanych przez użytkownika? Brzmi strasznie.

Nie widzę tu łamania zasady SRP, nie widzę wymuszenia jednej warstwy i nie widzę sensu przepisywania wszystkich potrzebnych propertów z obiektu z entity framework do jakiegoś POCO

No cóż, większość programistów nigdy nigdzie nie widzi łamania SRP.
A jeśli GUI aplikacji wie cokolwiek o bazie danych, to jest to jedna warstwa z definicji.

Ponieważ mamy jeden uniwersalny obiekt, to jest używany na wszystkich widokach w aplikacji. W efekcie mnożą się tam właściwości służące do wyświetlania czegoś (bo np. raz potrzebujemy formatu "imię nazwisko", a innym razem "nazwisko imię") i inne metody mające zastosowanie tylko w jednym miejscu. Do tego dochodzą jeszcze metody biznesowe (no bo w końcu nasz ORM model udaje encję domenową), walidacyjne (bo nie możemy zrobić prawidłowego always valid entity z walidacją w konstruktorze, lecz musimy mieć publiczne właściwości, bo to przecież EF), na dodatek walidacja jest kontekstowa, bo na każdym ekranie może być inna, itd...
W efekcie mamy mega spaghetti god object. No bo po co tworzyć oddzielne klasy do różnych celów?


Po dopracowaniu rozwiązania każdy będzie mógł założyć własny drzewiasty wątek.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)