Generyczny CRUD

0

Czołem koledzy programiści!
Chcę zaimplementować w swoim projekcie generyczną klasę, która odpowiadać będzie za tworzenie/edycję/usuwanie rekordów z bazy danych.

public class EntityStore<TEntity, TEntityCreateModel, TEntityUpdateModel> where TEntity : class, IEntity
    {
        private readonly StoreContext context;
        private readonly IMapper mapper;

        public EntityStore(StoreContext context, IMapper mapper)
        {
            this.context = context;
            this.mapper = mapper;
        }

        public void Create(TEntityCreateModel model)
        {
            context.Set<TEntity>().Add(mapper.Map<TEntity>(model));
            context.SaveChangesAsync();
        }

        public void Update(TEntityUpdateModel model)
        {
            var entity = context.Set<TEntity>().Find(model);

            context.Entry(entity).State = System.Data.Entity.EntityState.Modified;
            context.SaveChanges();
        }

        public void Delete(long id)
        {
            context.Set<TEntity>().Remove(context.Set<TEntity>().Find(id));
            context.SaveChanges();
        }
}

Zastosowanie powyższego rozwiązania wymaga, aby projekt Webowy posiadał referencję do projektu zawierającego klasy odwzorowujące bazę danych (klasa reprezentowana przez TEntity). Aczkolwiek bardzo często idzie tutaj przeczytać, iż jedynym do czego referencję powinien mieć Web to projekt z Kontraktami/Interfejsami. Czy to tak powinno wyglądać, czy jest inne rozwiązanie dla takiego generyka?

 public class ProductController : Controller
    {
        private readonly EntityStore<Product, ProductCreateModel, ProductUpdateModel> entityStore;

        public ProductController(EntityStore<Product, ProductCreateModel, ProductUpdateModel> entityStore)
        {
            this.entityStore = entityStore;
        }

        [HttpPost]
        public ActionResult Create(ProductCreateModel model)
        {
            if (ModelState.IsValid)
            {
                entityStore.Create(model);
                return View("List");
            }

            return View(model);
        }
    }

Pozdrawiam,
KK

0

Nie bardzo rozumiem czym ma się różnić u Ciebie ProductCreateViewModel od ProductUpdateViewModel, a te dwie klasy od klasy Product ? Tak by ta klasa generyczne przyjmowała niepotrzebnie 3 parametry zamiast jednego typu obiektów. J

Zwróć uwagę, że trakcie budowania jakiejś tam aplikacji webowej zazwyczaj mamy parę rozbudowanych rzeczy, teraz odpowiedz sobie również na kilka podstawowych pytań:

  • czy jeżeli będę mieć jakieś zaawansowane widoki np. koszyk produktów wraz z wartością zamówienia, informacjami adresowymi domyślnymi wprowadzonymi przez Ciebie + informacje o stanie magazynowym produktów (np. w koszyku wyświetla się informacja - mamy X tego produktu na stanie) to czy twoja architektura spełni takie wymagania
  • czy Twoja architektura w łatwy sposób pozwoli w sensowny na zrealizowanie takich zadań jak -> złożenie zamówienia-> obliczenia rabatów-> aktualizacje stanów magazynowych -> finalizacja zamówienia.
0

Generyczny CRUD to coś co fajnie wygląda w tutorialach. Nie widziałem tego w prawdziwej aplikacji.

1

Ja widziałem, ale nie tak trywialne.

Jeśli aplikacja jest to typowy CRUD, gdzie warstwa logiki biznesowej sprowadza się wyłącznie do przepchnięcia danych do/z bazy to takie podejście może się sprawdzić.
Jeśli logika jest bardziej rozbudowana to jak najbardziej da wykorzystać tego typu generyki, ale trzeba przewidzieć miejsca gdzie można będzie wprowadzić zmiany.

No i oczywiście trzeba zachować rozsądek i nie używać młotka do wkręcania śrub

1
Karol Krawczyk napisał(a):

Zastosowanie powyższego rozwiązania wymaga, aby projekt Webowy posiadał referencję do projektu zawierającego klasy odwzorowujące bazę danych (klasa reprezentowana przez TEntity). Aczkolwiek bardzo często idzie tutaj przeczytać, iż jedynym do czego referencję powinien mieć Web to projekt z Kontraktami/Interfejsami. Czy to tak powinno wyglądać, czy jest inne rozwiązanie dla takiego generyka?

Możesz mieć jakąś warstwę pośrednią między kontrolerem a EntityStore, która będzie znała zarówno view modele jak i persistence modele z EF.

kzkzg napisał(a):

Generyczny CRUD to coś co fajnie wygląda w tutorialach. Nie widziałem tego w prawdziwej aplikacji.

No, zdecydowanie częściej spotyka się brak generycznego CRUDa opakowany w architekturę enterprise. Efektem są tysiące zmarnowanych godzin na tworzenie 11 warstw kodu metodą kopiuj-wklej.

mariano901229 napisał(a):

Nie bardzo rozumiem czym ma się różnić u Ciebie ProductCreateViewModel od ProductUpdateViewModel, a te dwie klasy od klasy Product ? Tak by ta klasa generyczne przyjmowała niepotrzebnie 3 parametry zamiast jednego typu obiektów.

Przecież te nazwy są oczywiste - masz viewmodel do tworzenia, oddzielny do edycji, i persistence model/encję EF>

Zwróć uwagę, że trakcie budowania jakiejś tam aplikacji webowej zazwyczaj mamy parę rozbudowanych rzeczy, teraz odpowiedz sobie również na kilka podstawowych pytań:

  • czy jeżeli będę mieć jakieś zaawansowane widoki np. koszyk produktów wraz z wartością zamówienia, informacjami adresowymi domyślnymi wprowadzonymi przez Ciebie + informacje o stanie magazynowym produktów (np. w koszyku wyświetla się informacja - mamy X tego produktu na stanie) to czy twoja architektura spełni takie wymagania
  • czy Twoja architektura w łatwy sposób pozwoli w sensowny na zrealizowanie takich zadań jak -> złożenie zamówienia-> obliczenia rabatów-> aktualizacje stanów magazynowych -> finalizacja zamówienia.

W bardziej skomplikowanych (czyli nieCRUDowych) przypadkach nie musi przecież stosować tego podejścia, więc w czym problem?

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