2015-05-08 21 views
11

Niedawno spędziłem czas czytając na temat zasad SOLID i postanowiłem porównać porównanie bazy kodu, z którą pracuję.Posiadanie repozytorium zależne od innego repozytorium

W niektórych z naszych kodów znajduje się repozytorium (repozytorium A). Kiedy rekord ma zostać usunięty z repozytorium A, musimy również usunąć powiązany rekord z repozytorium B. Pierwotny koder stworzył więc zależność od konkretnej implementacji repozytorium B. Metoda w repozytorium A znajduje się w transakcji i usuwa rekord z repozytorium A, a następnie wywołuje metodę na repozytorium B, aby usunąć powiązane dane.

Moje zrozumienie zasady S polega na tym, że każdy obiekt powinien mieć tylko jeden powód do zmiany, ale moje repozytorium A ma 2 powody do zmiany? Czy jestem daleko od znaku?

Odpowiedz

26

Repozytorium powinno mieć jedną odpowiedzialność - utrzymywać jeden rodzaj podmiotu. Na przykład. pracowników. Jeśli musisz usunąć niektóre powiązane rekordy z innego repozytorium, wygląda to na logikę biznesową. Na przykład.

Kiedy pracownik jest zwolniony powinniśmy usunąć swój dziennik pracy

i zwyczajowe miejsce dla logiki biznesowej jest to usługi domeny. Usługa ta będzie miała zarówno repozytoriów i wykonać całą pracę:

staffService.Fire(employee) 

Wdrożenie będzie wyglądać

public class StaffService 
{ 
    private IEmployeeRepository employeeRepository; 
    private IWorkLogRepository workLogRepository; 
    private IUnitOfWorkFactory uowFactory; 

    // inject dependencies 

    public void Fire(Employee employee) 
    { 
     using(var uow = uowFactory.SartNew()) 
     { 
      workLogRepository.DeleteByEmployee(employee.Id); 
      employeeRepository.Delete(employee.Id); 
      uow.Commit(); 
     } 
    } 
} 

Więc podstawowy radzi

  • starać się utrzymać swoją logikę biznesową w jednym miejscu, nie rozsyłaj jej części do interfejsu użytkownika, części do repozytoriów, części do bazy danych (czasami z powodu problemów z wydajnością, musisz wykonać trochę logiki po stronie bazy danych, ale to jest wyjątek)
  • nigdy niech repozytoria odwoływać inne repozytoria, repozytorium jest bardzo komponent niskiego poziomu aplikacji z bardzo prostych zadań

Można zastanawiać się, co zrobić, jeśli masz pracownika i ma pewne zagnieżdżonego obiektu, który jest przechowywany w inna tabela bazy danych. Jeśli używasz tego obiektu oddzielnie od pracownika, wszystko jest jak wyżej - powinieneś mieć oddzielne repozytorium i jakiś inny obiekt (usługę), który manipuluje obydwoma repozytoriami. Ale jeśli nie użyjesz tego zagnieżdżonego obiektu osobno od pracownika, wówczas pracownik jest Korzeniem Aggregate i powinieneś mieć tylko repozytorium pracowników, które będzie sprawdzać obie tabele w środku.

+0

Niesamowita odpowiedź @Sergey to potwierdza moje przemyślenia, rozmawiałem z architektem systemu i zasugerował, że jest cienka linia między tym, czy jest to warstwa biznesowa, czy warstwa danych, ale ponieważ oczyszcza dane, to dobrze jest mieć je w warstwie danych. Mam nadzieję, że uda mi się go przekonać do przeniesienia go do warstwy biznesowej. – MrGrumpy

+0

Reguły usuwania powinny zazwyczaj być ostatecznie spójne, a nie silnie spójne. Ponadto rzadko zdarza się, aby faktycznie nastąpiło fizyczne usunięcie. 'employee.fire() -> EmployeeFired (employeedId) -> EventSubscriber -> ...'. – plalx

+2

Repozytorium nie powinno odwoływać się do innego repozytorium? może, ale przypuśćmy, że mam klasę A, która zawsze potrzebuje zagnieżdżonej klasy B (wymagana do pracy), ale sam obiekt klasy B może działać sam. Gdy moja usługa pobierze obiekt klasy A z repozytoriumA, to repozytorium będzie musiało użyć repozytoriumB, aby ponownie uzyskać objB i przypisać je do obiektu objA (przy użyciu fabryki): 'Repozytorium klasyA { publiczny ClassA GetById (id łańcucha) {objB = repositoryB.GetById (idB); factory.CreateObjA (idA, objB); } } ' Jak należy postąpić, aby uniknąć odniesienia między repozytoriami? – Jonathan

-2

W takim przypadku należy użyć wzoru event dispatcher.

Po operacja usuwania na RepoA można wysyłką zdarzenia jak:

dispatch repositoryA.deleted(RecordA) 

które przechowuje informacje o usuniętej rekordu.

Listing wentylacyjny następnie subskrybuje na takie zdarzenie i, mając repozytorium B jako zależność, wtedy wywoła usuwanie.

użyjmy B jak nazwa podmiotu, deklaracja słuchacz powinien brzmieć następująco:

Listen RepositoryA.delete and invoke onDelete(Event) 

Z takim podejściem zostały zrealizowane luźne sprzężenie pomiędzy repoA i repoB (wykonującego Open/Close zasadę - z bliska-) więc repoA mają teraz (znowu)

pozdrowienia.

Powiązane problemy