2015-05-08 29 views
11

Recentemente ho passato un po 'di tempo a leggere i principi SOLID e ho deciso di vedere in che modo il codice base con cui lavoro si confronta.Avere un repository dipendente da un altro repository

In alcuni dei nostri codici è presente un repository (repository A). Quando un record deve essere cancellato dal repository A, dobbiamo anche cancellare un record associato dal repository B. Il coder originale ha quindi creato una dipendenza da un'implementazione concreta del repository B. Il metodo nel repository A è all'interno di una transazione e elimina il record dal repository A e quindi chiama il metodo sul repository B per eliminare i dati associati.

La mia comprensione del principio S è che ogni oggetto dovrebbe avere solo 1 motivo per cambiare, ma al mio repository A ci sono 2 motivi per cambiare? O sono lontano dal marchio?

risposta

26

Il repository dovrebbe avere un'unica responsabilità - persiste un tipo di entità. Per esempio. dipendenti. Se devi eliminare alcuni record associati da un altro repository, sembra una logica aziendale. Per esempio.

Quando dipendente viene licenziato dovremmo rimuovere il suo registro lavoro

E solito posto per la logica di business è un servizi di dominio. Questo servizio avrà entrambi i repository e fare tutto il lavoro:

staffService.Fire(employee) 

Attuazione sarà simile

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(); 
     } 
    } 
} 

Così, di base ti ricorda

  • cercare di mantenere la logica di business in un unico luogo, non diffondetene parte nell'interfaccia utente, parte di essa in repository, parte nel database (a volte a causa di problemi di prestazioni dovete fare un po 'di logica sul lato del database, ma questa è un'eccezione)
  • non lasciare mai che i repository di riferimento altri repository, repository è una componente molto basso livello dell'applicazione con molto semplici responsabilità

Vi chiederete che cosa fare se si dispone di dipendenti e ha un oggetto nidificato che viene memorizzato nel tabella di database diversa. Se si utilizza quell'oggetto separatamente dal dipendente, allora tutto è come sopra: si dovrebbe avere un repository separato e qualche altro oggetto (servizio) che manipola entrambi i repository. Ma se non si utilizza tale oggetto nidificato separatamente dal dipendente, il dipendente è una radice aggregata e si dovrebbe avere solo il repository dipendente, che interrogherà entrambe le tabelle all'interno.

+0

Risposta impressionante @Sergey conferma i miei pensieri, ho parlato con l'architetto di sistema e mi ha suggerito che è una linea sottile tra il livello aziendale o il livello dati, ma poiché ripulisce i dati va bene averlo nel livello dati. Spero di poterlo convincere a spostarlo sul livello aziendale – MrGrumpy

+0

Le regole di cancellazione dovrebbero in genere essere coerenti alla fine piuttosto che coerenti. Inoltre, è piuttosto raro che si verifichi effettivamente un'eliminazione fisica. 'employee.fire() -> EmployeeFired (employeedId) -> EventSubscriber -> ...'. – plalx

+2

Il repository non dovrebbe fare riferimento a un altro repository? forse, ma supponiamo che io abbia ClassA che ha sempre bisogno di un ClassB annidato (richiesto per funzionare), ma l'oggetto ClassB stesso può funzionare da solo. Quando il mio servizio recupera un oggetto ClassA dal repositoryA, questo repository dovrebbe utilizzare repositoryB per recuperare objB e assegnarlo a objA (utilizzando una factory) come questo: 'class RepositoryA { public ClassA GetById (stringa id) {objB = repositoryB.GetById (idB); factory.CreateObjA (idA, objB); } } Come dovrebbe essere fatto per evitare il riferimento tra i repository ?? – Jonathan

-2

In questo caso è necessario utilizzare il modello event dispatcher.

Dopo l'operazione di eliminazione sul RepoA è possibile inviare un evento come:

dispatch repositoryA.deleted(RecordA) 

che conterrà le informazioni del record eliminato.

Un lister di ventilazione quindi si iscriverà su tale evento e, avendo il repository B come dipendenza invocherà una cancellazione.

Let uso B come il nome dell'entità, la dichiarazione ascoltatore dovrebbe suonare come:

Listen RepositoryA.delete and invoke onDelete(Event) 

Con questo approccio si è realizzato un accoppiamento lasco tra repoA e repoB (far rispettare il/Chiudi linea di principio - sul lato vicino-) quindi repoA hanno ora (di nuovo)

saluti.

Problemi correlati