Gdzie powinno się korzystać z LINQ?

0

Cześć, korzystam ze wzorca repozytorium i zastanawia mnie jedna rzecz. Czy poniższy kod łamie idee wzorca MVC? Chodzi mi o to czy prawidłowym jest wywoływanie metod biblioteki Linq bezpośrednio w danej akcji kontrolera? A może obiekt repository winien zawierać metodę, dajmy na to: "UserDate" która będzię zawierać ten kod??

public PartialViewResult Index()
{
    List<Users> user= repository.Users.Where(d => d.visitDate.Day == DateTime.Now.Date.Day).ToList();
    return PartialView(visit);
}

sformatowanie kodu - @furious programming

0

Możesz sobie odpowiedzieć na to pytanie z perspektywy jak najlepiej byłoby przetestować obydwa rozwiązania:

  1. Filtrowanie użytkowników w repository => musiałbyś przetestować swoją implementację, czyli jeśli używasz np. EF to musiałbyś to robić w połączeniu z jakąś testowa bazą.
  2. Filtrowanie tak jak to zrobiłeś teraz => w teście tworzysz instancje kontrolera do której podajesz "atrapę" swojego repozytorium.
    Optowałbym za 2.
2
KilaZ napisał(a):

Cześć, korzystam ze wzorca repozytorium i zastanawia mnie jedna rzecz. Czy poniższy kod łamie idee wzorca MVC?

Ten kod łamie nie tylko ideę MVC, ale przede wszystkim ideę repozytorium.

KilaZ napisał(a):

A może obiekt repository winien zawierać metodę, dajmy na to: "UserDate" która będzię zawierać ten kod??

Raczej GetUsersByDate. Wtedy będziesz miał repozytorium. Wszystkie selekcje, filtrowania, sortowania powinny odbywać się w metodach repozytorium.

Natomiast MVC łamiesz, bo używając repozytorium w kontrolerze jednocześnie umieszczasz w kontrolerze logikę biznesową gdy powinna ona się znajdować wyłącznie w modelu.

Wielki Szczur napisał(a):

Możesz sobie odpowiedzieć na to pytanie z perspektywy jak najlepiej byłoby przetestować obydwa rozwiązania:

#1 Filtrowanie użytkowników w repository => musiałbyś przetestować swoją implementację, czyli jeśli używasz np. EF to musiałbyś to robić w połączeniu z jakąś testowa bazą.

#2 Filtrowanie tak jak to zrobiłeś teraz => w teście tworzysz instancje kontrolera do której podajesz "atrapę" swojego repozytorium.

Optowałbym za 2.

Przecież to są dwie oddzielne kwestie.
Jeśli testujemy działanie repozytoriów, to musimy testować konkretne ich implementacje, a więc pisać testy korzystające z bazy danych, czyli są to testy integracyjne.
Natomiast w testach reszty aplikacji repozytoria się mockuje. Jeśli mamy normalne repozytoria (a nie jakąś generyczną cieknącą abstrakcję) z konkretnymi metodami zwracającymi konkretne zestawy danych, to ich mockowanie to banał.

0

Natomiast MVC łamiesz, bo używając repozytorium w kontrolerze jednocześnie umieszczasz w kontrolerze logikę biznesową gdy powinna ona się znajdować wyłącznie w modelu.

Dziwne bo przerabiałem jedną z literatur jaką jest Pro ASP.NET MVC 4 i w niej korzystali właśnie tak z repozytoriów. Fragment z książki.

 
public class AdminController : Controller {

 private IProductRepository repository;
 public AdminController(IProductRepository repo) {
 repository = repo;
 }

 public ViewResult Index() {
 return View(repository.Products);
 }

} 

W takim razie jak poprawnie używać repozytoriów nie łamiąc MVC ?

2

W takim razie jak poprawnie używać repozytoriów nie łamiąc MVC ?

Ja stosuje takie troche pokrecone rozwiazanie:
#Interfejsy konkretnych repozytoriow wrzucam do projektu Core/Business/Whatever
#Implementacje konkretnych repozytoriow oraz bazowe generyczne repozytorium pcham do projektu DataAccess
#Przykladowa metoda z repozytorium wyglada tak:

    public PagedList<Question> FindNewestQuestionsByTag(string tag, PagingRequest request)
    {
      var questions =
        from question in Session.Query<Question>()
        where question.Tags.Any(t => t.Name == tag)
        orderby question.CreatedAt
        select question;

      return questions.AsPagedList(request);
    }

#W testach odpalam instancje sqlite w pamieci i wykonuje to na zywej bazie.
#W testach czegos innego poza repozytorium, mockuje sobie taka metode i nie tykam bazy w ogole.

Wady: PagingRequest leci przez 3/4 aplikacji. :\

0

Bardziej klasyczne podejście:

public class UserRepository : IUserRepository, IDisposable
{
	public IEnumerable<Users> GetUsersByDate(DateTime dateTime)
	{
		return context.Users.Where(d => d.visitDate.Day == dateTime.Date.Day);
	}
}
// ...

public PartialViewResult Index()
{
    List<Users> users = userRepository.GetUsersByDate(DateTime.Now).ToList();
    return PartialView(visit);
}

2
KilaZ napisał(a):

Dziwne bo przerabiałem jedną z literatur jaką jest Pro ASP.NET MVC 4 i w niej korzystali właśnie tak z repozytoriów.

Nie jest to dziwne. Większość ludzi nie rozumie ani wzorca repozytorium (uznając go za warstwę dostępu do bazy danych) ani MVC (myśląc, że Model = baza danych, a Kontroler odpowiada za wszystko: logikę prezentacji, aplikacji i biznes, a w ogóle to MVC oznacza aplikację trójwarstwową).
Co nie zmienia faktu, że jest to dobra książka, jeśli chcemy się nauczyć technologii ASP.NET MVC, ale nie projektowania sensownych aplikacji.

A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection.

źródło: http://martinfowler.com/eaaCatalog/repository.html
A tutaj dobre wyjaśnienie: http://www.sapiensworks.com/blog/post/2012/02/22/The-Repository-Pattern-Explained.aspx
i dobry zestaw rad: http://www.sapiensworks.com/blog/post/2013/10/07/Tips-And-Tricks-For-The-Repository-Pattern.aspx

In the MVC paradigm the user input, the modeling of the external world, and the visual feedback to the user are explicitly separated and handled by three types of object, each specialized for its task. The view manages the graphical and/or textual output to the portion of the bitmapped display that is allocated to its application. The controller interprets the mouse and keyboard inputs from the user, commanding the model and/or the view to change as appropriate. Finally, the model manages the behavior and data of the application domain, responds to requests for information about its state (usually from the view), and responds to instructions to change state (usually from the controller).

źródło: http://st-www.cs.illinois.edu/users/smarch/st-docs/mvc.html
Trochę więcej na ten temat: http://www.martinfowler.com/eaaDev/uiArchs.html
I jeszcze więcej: http://lostechies.com/derekgreer/2007/08/25/interactive-application-architecture/

W takim razie jak poprawnie używać repozytoriów nie łamiąc MVC ?

Kontrolery powinny być jak najprostsze, powinny jedynie obsługiwać żądania użytkownika, wywoływać operacje na Modelu i przekierowywać do odpowiednich Widoków.

Ja robię tak, że z kontrolera wołam metodę application service czyli klasy, która stanowi zbiór procesów biznesowych aplikacji. Dane od tego serwisu do Kontrolera i z powrotem przekazuję za pomocą ViewModeli. Application service może być dowolnie skomplikowana, w prostym przypadku sama przeprowadzi operacje bezpośrednio na encjach i kontekście EF (albo lepiej ISession z NHibernate), a jeśli logika aplikacji jest bardzo skomplikowana, to nic nie szkodzi, żeby application service ukrywał przed kontrolerami model zbudowany zgodnie z DDD... Możliwości są nieograniczone, należy je tylko dopasować do złożoności naszych problemów.
Jeśli aplikacja ma mieć miliard użytkowników, to application service łatwo przerobić na web service, i postawić na oddzielnym serwerze. Przy moim podejściu niemalże gratis mamy warstwy fizyczne, gdy tylko będą potrzebne.
No i najważniejsze - dzięki temu oddzielona jest aplikacja (czyli oprogramowane procesy biznesowe) od swoich klientów. Bo aplikacja webowa napisana w ASP.NET MVC to jeden z możliwych klientów aplikacji. Mogą też być inne. A najważniejszym klientem, który powinien powstać jeszcze przed napisaniem kodu aplikacji, są testy jednostkowe.

A wady? Trzeba to napisać... a dużo łatwiej wstawić generyczne repozytorium w kontrolery i tworzyć spaghetti. No, ale to dobre spaghetti, w końcu mamy modne MVC i powszechnie uznawane za profesjonalizm repozytoria, więc jesteśmy modni, profesjonalni i wielowarstwowi... zupełnie jak Shrek.

0

Super i dziękuje za wyczerpującą odpowiedz, pozdrawiam :)

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