Generyczne repozytoria- czy to w ogóle ma jakiś sens?

0

Przeglądałem dziś kilka kursów programowania Api w NetCore i wszędzie jeśli jest użyty Entity Framework pojawiają się repozytoria generyczne, czyli mamy

public interface IDataService<T>
    {
        Task<IEnumerable<T>> GetAll();
        Task<T> Get(int id);
        Task<T> Create(T entity);
        Task<T> Update(int id, T entity);
        Task<bool> Delete(int id);
    }

Czy to ma jakiś sens w praktycznym programowaniu? Bo dla mnie to istnieje tu tylko sens akademicki, pomimo ze autorzy kursu twierdzą ze pokazują przykład praktycznego zastosowania w aplikacji. Szczególnie nie pasują mi metody Get(int id) i GetAll(). Pierwsza dlatego ze przeważnie potrzeba więcej warunków, żeby określić co chcemy dostać, a druga, że bez sensu pobierać wszystko i też wedlug mnie powinna być sparametryzowana.
Czy stosować takie generyczne twory? Jeśli miałbym tego uzywać to sądzę ze byłoby tam co najmniej kilka metod Get z różnyumi parametrami. Czy dobrze wnioskuję?

4
kalimata napisał(a):

Bo dla mnie to istnieje tu tylko sens akademicki, pomimo ze autorzy kursu twierdzą ze pokazują przykład praktycznego zastosowania w aplikacji.

To nie ma sensu nawet akademickiego, a co dopiero praktycznego, ani w przypadku EF ani innych ORM. Unikaj takich tutoriale, najlepiej też ich autorów. W takich przypadkach zazwyczaj nieszczęścia chodzą parami i obok pewnie są inne raczyska jak repozytoria per tabela.

Przykładowe problemy z generycznymi repozytoriami:

  1. Rzadko które obiekty z bazy się usuwa. Będziesz rzucał tam jakieś wyjątki?
  2. GetAll będzie pakować całą bazę do aplikacji? Tego nawet nikt w tych ToDoAppach nie zauważa, bo danych jest mało, ale to nie zadziała w żadnej sensownej aplikacji.
1
Saalin napisał(a):

W takich przypadkach zazwyczaj nieszczęścia chodzą parami i obok pewnie są inne raczyska jak repozytoria per tabela.

Zaraz pewnie pojawi się magiczne słowo DDD, ale jak tak patrzę, to @somekind miał rację pisząc, że repozytoria bez DDD nie mają sensu. Jak mamy agregaty i jest repozytorium per agreagat, to jest ładnie. Gorzej, jak każda encja ma swoje repozytorium i te encje mają jeszcze referencje do innych encji, wtedy robi się bałagan, bo np. okazuje się, że jedną encję można zapisać przez 2 repozytoria.

0

Też bym nie chciał żeby tu pojawił się temat DDD ,bo w tym nie robie i z tego co tu na forum wyczytałem tylko tam jest sensowne uzywać okreslenia repozytorium.

Piszecie jak nie powinno się robić. A w takim razie jak **powinno **sie robić?

Czy jak mam np tabele User i Address to poprawne będzie zrobić:
Ja po swojemu bym to zrobił w sposob ze np mam tabele z użytkownikami to robie

public interface IUserService
    {
      
        Task<User> Get(int id);
         Task<User> GetByName(string name);
        Task<User> Create(User entity);
        Task<User> Update(int id, User entity);
        Task<bool> Delete(int id);
//... inne medoty z warunkami
    }

i w jakiejś implementacji tego interfejsu

public class UserService : IUserService
    {

private readonly DbContext context;

public UserService(DbContext c)
{
context = c;
}

  public async Task<User> GetByName(string name)
{
return await context.Users.FirstOrDefaultAsync(u=>u.Name==name);
}

// implementacja pozostałych elementów
    }

i podobnie obsługa adresów

0

@Saalin:

  1. GetAll będzie pakować całą bazę do aplikacji? Tego nawet nikt w tych ToDoAppach nie zauważa, bo danych jest mało, ale to nie zadziała w żadnej sensownej aplikacji.

Generalnie to nie jest problem, bo w parametrze Geta możesz przekazać listę Expression<Func<T, bool>> i zostaną wykorzystane twoje silnie typowane lambdy które możesz wykorzystać jako predykaty w Where, tak samo JOINy.

1

@WeiXiao: a przekazywanie Expression<Func<T,bool>> nie uzależnia Cię przypadkiem od ORMa, który siedzi pod spodem? Bo jak byś chciał użyć Dappera albo jakąś funkcję SQLową odpalić, to już nie tak łatwo by było przekazać tam ten expression afaik.

0

@nobody01: to wygeneruj sobie sql z expressionów i cześć ;)

masz rację

3

Repozytorium operuje na obiektach domenowych, nie zaś obiektach z ORM, to jest różnica ;)

0

per encję bazodanową mało sensowne, na domenie tak - a jakie słowo ktoś do tego dorobi ... czy DAO, czy repozytorium, generalnie te słowa są nadużywane / używane często nieprawidłowo. Ważny sens.

Nowoczesne metody dostępu do baz danych są na tyle generyczne same w sobie, że dodatkowy poziom dostępu do encji bazodanowej nie ma sensu

0

Czyli najlepiej zrobić tak jak napisałem w drugim przykładzie,?

public async Task<User> GetByName(string name)
{
return await context.Users.FirstOrDefaultAsync(u=>u.Name==name);
}

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