Scrivere esplicitamente usando (...) {...} o nascondendolo?

2

Oggi ho discusso con il nostro architetto sulla scrittura usando le istruzioni in WorkUnits.

Supponiamo di avere un oggetto PersonWork con metodi:

public class PersonWorkUnit 
{    
    private IContextFactory contextFactory;
    private IRepositoryFactory repositoryFactory;

    public PersonWorkUnit(IContextFactory contextFactory, IRepositoryFactory repositoryFactory)
    {
        this.contextFactory = contextFactory;
        this.repositoryFactory = repositoryFactory;
    }

    public Person Get(int id) 
    {
         using(var context = this.contextFactory.Create<IPersonContext>())
         {
              var personRepo = this.repositoryFactory.Create<IPersonRepository>(context);
              return personRepo.Get(id);
         }
    }
}

Ciò che non gli piace è che dobbiamo scrivere using(var context = this.contextFactory.Create<IPersonContext>()) { var personRepo = this.repositoryFactory.Create<IPersonRepository>(context); in ogni metodo di WorkUnit.

La mia opinione è che sia bello scrivere (e leggere) in ogni metodo, perché è possibile vedere in modo esplicito la durata del contesto e ciò che viene fatto durante, o prima / dopo il contesto. E se hai un negozio dove hai bisogno di più repository.

La sua opinione è che è sbagliato "duplicare" questo codice in ogni metodo della classe e vuole "nasconderlo" in un aspetto a livello di metodo (attributo).

Qual è la tua opinione su questo argomento?

Non vedo l'ora di approfondimenti e ragioni / vantaggi / svantaggi per le soluzioni.

Grazie in anticipo

Modifica: per rispondere ad alcune domande

  • Che cos'è un contesto?
    Con contesto intendo un'entità framework DbContext
  • Perché avere un ContextFactory?
    Voglio avere una fabbrica quindi non ho new PersonContext() e posso prendere in giro DbContext nei test di accettazione con InMemoryDbContext
  • Cos'è un repository?
    Repository (e solo repository) sono responsabili dell'accesso al database (DbContexts)
  • Che cos'è una work unit? In WorkUnits abbiamo metodi che corrispondono a casi d'uso. Un caso d'uso potrebbe aver bisogno di più (diversi) repository. In un metodo WorkUnit ci potrebbe essere qualcosa di più di una semplice chiamata a un repository ... l'esempio sopra è semplificato
  • Perché non usare ContextFactory nei repository? Poiché alcuni casi d'uso richiedono più repository e voglio che usino lo stesso contesto, in modo che se qualcosa fallisce, l'intera transazione viene ripristinata
posta xeraphim 27.09.2017 - 11:31
fonte

3 risposte

6

Dal modo in cui descrivi il tuo codice, sembra che PersonWorkUnit abbia un insieme di metodi che seguono tutti il seguente formato:

public SomeType Foo(...) 
{
    using(var context = this.contextFactory.Create<IPersonContext>())
    {
        var personRepo = this.repositoryFactory.Create<IPersonRepository>(context);
        // do something with personRepo to create SomeType instance
        // return SomeType
    }
}

Se questo è il caso, usa semplicemente i delegati per creare un singolo metodo che faccia tutto ciò che esclude le righe commentate e forniscile con un Func<> :

public Person Get(int id) => ProcessPersonRepo(p => p.Get(id));

private T ProcessPersonRepo<T>(Func<IPersonRepository, T> specificBehaviour) 
{
    using(var context = contextFactory.Create<IPersonContext>())
    {
        var personRepo = repositoryFactory.Create<IPersonRepository>(context);
        return specificBehaviour(personRepo);
    }
}
    
risposta data 27.09.2017 - 14:08
fonte
1

Forse è solo il tuo esempio ma questo codice mi sembra strano. un odore di codice, se vuoi.

Hai quattro oggetti che hanno il controllo possibile della connessione db

  • La fabbrica del contesto
  • Il repository
  • L'unità di lavoro
  • Il contesto stesso

Posso capire perché potresti volere tutto questo, ma è una configurazione piuttosto complessa.

Sono sicuro che il tuo esempio è intenzionalmente limitato, ma solleva alcune domande sui possibili modi per semplificare il codice.

  • Se i metodi dell'unità di lavoro rispecchiano i repository, perché non li hanno affatto? Basta chiamare il repository.

  • Il factory di contesto potrebbe non essere parte del repository? Forse usa un costruttore di stringhe di connessione.

  • Quale valore viene aggiunto creando un nuovo repository su ogni chiamata? Non potresti semplicemente iniettare il repository?

  • Se i metodi della tua unità di lavoro sono più grandi dell'esempio, Transaction Scope sarebbe un metodo alternativo per controllare l'unità?

Se il tuo codice di vita reale giustifica l'uso di tutti e quattro gli oggetti e ognuno ha una chiara responsabilità, allora:

Sì, la sua buona pratica è quella di eliminare il contesto dopo l'uso e ...

No, direi che spostare il blocco usando ad un Aspect Orientated Attribute getta semplicemente un'altra complessità in uno scenario già complesso e offusca invece di semplificare il codice.

    
risposta data 27.09.2017 - 12:08
fonte
-2

Affrontare il contesto e gli oggetti del repository sono preoccupazioni relative al livello di accesso ai dati e devono essere separati dai propri oggetti di business, che è ciò che appare PersonWorkUnit. Dovresti avere una classe di accesso ai dati che gestisce solo l'utilizzo del contesto e del repository. questo renderebbe più semplice il tuo codice aziendale avendo solo qualcosa come dataGetter.GetPerson(Id); nel tuo metodo get. Se conosci la persona di cui hai bisogno alla creazione di PersonWorkUnit, puoi anche spostare questa chiamata al costruttore che semplificherà il codice che chiama anche PersonWorkUnit. Tutto il brutto codice della piastra della caldaia è quindi in dataGetter dove può essere ignorato per la maggior parte.

L'obiettivo di questa configurazione è mantenere la separazione dei problemi, in modo che la logica aziendale non debba gestire la logica dell'infrastruttura e consente inoltre di seguire il principio di open closed. con il tuo progetto di esempio PersonWorkUnit deve cambiare se le regole di accesso ai dati cambiano e se cambiano le regole aziendali sulla persona. Avendo una classe dataGetter che restituisce una persona, l'unica ragione per cui PersonWorkUnit deve essere modificata è perché la logica aziendale cambia.

    
risposta data 27.09.2017 - 14:28
fonte

Leggi altre domande sui tag