To bezpośrednio na DataContext operujesz?
W przypadku Entity Frameworka owszem, w przypadku NHibernate korzystam z odpowiednika czyli Session.
Według mnie zawsze uzasadnione jest ukrywanie skąd pochodzi źródło danych.
A ORM tego nie ukrywa wystarczająco? Z ORMem pracuje się z grubsza tak, jak ze zwykłymi kolekcjami obiektów w pamięci.
Jeżeli zmieni się specyfika (dostęp będzie odbywał się np. poprzez czytanie plików z dysku/sieci) lub wystąpi wymiana ORM, wtedy w prosty sposób sobie poradzimy.
Wiedziałem, że ktoś użyje tego argumentu. :)
A zmieniła się kiedykolwiek w jakimkolwiek projekcie? Ktoś kiedyś zmienił bazę danych na pliki? Zaczynając projekt wybieramy języki, technologie i bazy danych, a potem się tego trzymamy.
Ale nawet jeśli, to co za problem? Wystarczy użyć innego providera do ORMa, i już możemy zmienić bazę danych. Nawet na pliki, jak się uprzemy.
Do tego dochodzi testowanie jednostkowego, które IMO nie powinno się odbywać, gdy operujemy bezpośrednio na IQueryable.
Dlatego powinniśmy pisać tak kod, żeby logikę biznesową dało się przetestować bez udziału bazy danych. Chociaż testy integracyjne nie są niczym złym, wręcz przeciwnie.
Co jest złego w Repository?
Zaczyna się od CustomerRepository
z metodami GetCustomerById
, GetCustomerByName
, GetCustomerByNIP
. Wszystko jest fajnie. Potem okazuje się, że trzeba pobrać klienta razem z fakturami, więc ktoś zmienia zawartość tych metod tak, że zachłannie pobierane są faktury. Oczywiście nigdzie w kodzie tego nie widać, do repozytorium nikt inny nie zagląda (bo po co?), ale ludzie dziwią się, że w wielu miejscach aplikacja zwolniła... Na szczęście znalezienie przyczyny nie trwa długo, i trzeba to naprawić. Więc co się robi? Nowe metody o więcej mówiących nazwach: GetCustomerWithInvoicesById
, GetCustomerWithInvoicesByName
, GetCustomerWithInvoicesByNIP
. I jest wszystko dobrze!
Przynajmniej na razie, bo z czasem pojawia się potrzeba pobrania klientów wg adresu wraz z jego pracownikami, ale bez faktur: GetCustomersWithEmployeesButWithoutInvoicesByAddress
, a potem potrzeba pobrania wszystkich klientów, z fakturami, bez pracowników, z ulubionymi filmami, bez kochanek wg grupy krwi żony i imienia kota córki prezesa: GetCustomersWithInvoicesWithoutEmployeesWithFavouriteMoviesWithoutMistressesByWifeBloodTypeAndChairmanDaughterCatName
.
Im bardziej skomplikowana domena tym więcej potrzeb kombinacji warunków i wyciągania powiązanych encji, tym więcej metod w klasie Repozytorium. Kończymy z klasą z milionem metod... i to ma być dobre?
http://martinfowler.com/eaaCatalog/repository.html
A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. Client objects construct query specifications declaratively and submit them to Repository for satisfaction. Objects can be added to and removed from the Repository, as they can from a simple collection of objects, and the mapping code encapsulated by the Repository will carry out the appropriate operations behind the scenes. Conceptually, a Repository encapsulates the set of objects persisted in a data store and the operations performed over them, providing a more object-oriented view of the persistence layer. Repository also supports the objective of achieving a clean separation and one-way dependency between the domain and data mapping layers.
A teraz zamieńmy w tej definicji "Repository" z "ORM", i zobaczmy, że nadal będzie ona prawdziwa. Repozytorium ORMowi nie daje absolutnie nic. To tylko kolejna warstwa kodu, która może spowodować błędy.
Czyli jeżeli mam podstawowe klasy, które reprezentują encje i nagle mam widzimisie , że chce zwrócić coś nietypowego ( kilka pól z jednej tabeli i kilka pól z drugiej tabeli ) to muszę tworzyć ku temu osobną klasę tak?
No raczej... Chyba, że masz inny pomysł, ale to jest generalnie najprostsze. Porządny ORM bez problemu Ci pozwoli wypełnić taką klasę danymi z bazy.
Swoją drogą ORM-a nie zawsze każdy używa ( przecież nie jest chyba super wymagany w każdym projekcie ).
No nie jest wymagany. Ale w zależności od tego, czy płacą nam za godzinę, czy nie, to nie używając ORMa okradamy albo swojego pracodawcę/klienta z pieniędzy, albo siebie z czasu.
Ale jeżeli już ORM, to jak to rozwiązać skoro jako Model chcę zastosować mapowane klasy na tabele i każda klasa mapowana ma jakąś logikę.
Klasy mapowane na tabele to raczej encje, ale mniejsza z tym. Jeśli chcesz zaszywać logikę w tych klasach, to też nie ma problemu, tylko niech to nie będzie logika operacji bazodanowych, jak pytałeś w innym wątku.