Creazione di un livello di astrazione sul livello ORM

11

Credo che se i tuoi repository utilizzano un ORM è già abbastanza astratto dal database.

Tuttavia, dove sto lavorando ora, qualcuno crede che dovremmo avere un livello che astragga l'ORM nel caso in cui vorremmo cambiare l'ORM in seguito.

È davvero necessario o è semplicemente un po 'troppo impegnativo creare un livello che funzioni su molti ORM?

Modifica

Solo per dare maggiori dettagli:

  1. Abbiamo classe POCO ed Entity Class mappate con AutoMapper. Le classi di entità vengono utilizzate dal livello del repository. Il livello del repository quindi usa lo strato aggiuntivo di astrazione per comunicare con Entity Framework.
  2. Il livello aziendale non ha in alcun modo un accesso diretto a Entity Framework. Anche senza il livello aggiuntivo di astrazione sull'ORM, questo deve utilizzare il livello di servizio che utilizza il livello del repository. In entrambi i casi, il livello aziendale è completamente separato dall'ORM.
  3. L'argomento principale è di essere in grado di modificare ORM in futuro. Dal momento che è veramente localizzato all'interno del livello del repository, per me è già ben separato e non vedo perché sia necessario un ulteriore livello di astrazione per avere un codice di "qualità".
posta Patrick Desjardins 19.10.2012 - 20:06
fonte

3 risposte

10

In questo modo giace la follia. È altamente improbabile che sia necessario modificare gli ORM. E se decidessi di cambiare l'ORM, il costo della riscrittura dei mapping sarà una piccola parte del costo per sviluppare e mantenere il tuo meta-ORM. Mi aspetto che tu possa scrivere alcuni script per fare il 95% del lavoro necessario per cambiare ORM.

Le strutture interne sono quasi sempre un disastro. Costruirne uno in previsione dei bisogni futuri è quasi un disastro garantito. I quadri di successo sono estratti da progetti di successo, non costruiti in anticipo per soddisfare esigenze immaginarie.

    
risposta data 19.10.2012 - 21:34
fonte
12

L'ORM fornisce un'astrazione affinché il livello dati sia indipendente dal suo RDBMS, ma potrebbe non essere sufficiente per "slegare" il livello aziendale dal livello dati. In particolare, non dovresti lasciare che gli oggetti che si associano alle tabelle RDBMS "perdano" direttamente nel livello aziendale.

Per lo meno, il tuo livello aziendale deve programmare su interfacce che gli oggetti mappati da tabella gestiti da ORM dal livello dati potrebbero potenzialmente implementare. Inoltre, potrebbe essere necessario creare un livello basato su un'interfaccia di creazione di query astratta per nascondere le funzionalità di query native del tuo ORM. L'obiettivo principale è evitare di "cuocere" qualsiasi ORM specifico nella soluzione oltre il livello dati. Ad esempio, potrebbe essere allettante creare stringhe HQL ( Hibernate Query Language ) nel livello aziendale. Tuttavia, questa decisione apparentemente innocente legherebbe il tuo livello aziendale a Hibernate, inchiodando così il business e i livelli di accesso ai dati; dovresti cercare di evitare questa situazione il più possibile.

EDIT: Nel tuo caso, il livello aggiuntivo all'interno del repository è una perdita di tempo: in base al punto numero due, il tuo livello aziendale è sufficientemente isolato dal tuo repository. Fornire ulteriore isolamento introdurrebbe una complessità inutile, senza ulteriori vantaggi.

Il problema con la creazione di un ulteriore livello di astrazione all'interno del tuo repository è che il particolare "marchio" di ORM determina il modo in cui interagisci con esso. Se costruisci un involucro sottile simile al tuo ORM, ma è sotto il tuo controllo, la sostituzione dell'ORM sottostante sarà più o meno dura che senza quel livello aggiuntivo. Se, d'altra parte, costruisci un livello che non assomiglia al tuo ORM, allora dovresti mettere in dubbio la tua scelta della tecnologia di mappatura relazionale dell'oggetto.

    
risposta data 19.10.2012 - 20:34
fonte
2

In genere, l'UnitOfWork fornisce questa astrazione. È un luogo che deve essere modificato, i repository dipendono da esso tramite un'interfaccia. Se hai mai bisogno di cambiare O / RM, basta implementare un nuovo UoW su di esso. Uno e fatto.

BTW va oltre il semplice passaggio di O / RM, pensa al test dell'unità. Ho tre implementazioni di UnitOfWork, una per EF, una per NH (perché in realtà dovevo passare da O / RM a metà progetto per un cliente che desiderava il supporto Oracle) e uno per la persistenza di InMemory. La persistenza di InMemory era perfetta per i test unitari o anche per la prototipazione rapida prima che io fossi pronto a mettere un database dietro di esso.

Il framework è semplice da implementare. Per prima cosa hai la tua interfaccia IRepository generica

public interface IRepository<T>
  where T:class
{
  IQueryable<T> FindBy(Expression<Func<T,Bool>>filter);
  IQueryable<T> GetAll();
  T FindSingle(Expression<Func<T,Bool>> filter);
  void Add(T item);
  void Remove(T item);

}

E l'interfaccia IUnitOfWork

public interface IUnitOfWork
{
   IQueryable<T> GetSet<T>();
   void Save();
   void Add<T>(T item) where T:class;
   void Remove<T>(T item) where T:class;
}

Il prossimo è il repository di base (la tua scelta se debba essere o meno astratta

public abstract class RepositoryBase<T>:IRepository<T>
  where T:class
{
   protected readonly IUnitOfWork _uow;

   protected RepositoryBase(IUnitOfWork uow)
   { 
      _uow=uow;
   }

   public IQueryable<T> FindBy(Expression<Func<T,Bool>>filter)
   {
      return _uow.GetSet<T>().Where(filter);
   }

   public IQueryable<T> GetAll()
   {
      return _uow.GetSet<T>();
   }

   public T FindSingle(Expression<Func<T,Bool>> filter)
   {
      return _uow.GetSet<T>().SingleOrDefault(filter);
   }

   public void Add(T item)
   {
      return _uow.Add(item);
   }

   public void Remove(T item)
   {
      return _uow.Remove(item);
   }
}

L'implementazione di IUnitOfWork è un gioco da ragazzi per EF, NH e In Memory. Il motivo per cui rendo IQueryable, è per lo stesso motivo, Ayende menziona nel suo post, il client può ulteriormente filtrare, ordinare, raggruppare e persino proiettare il risultato usando LINQ e si ottiene comunque il vantaggio che tutto venga fatto lato server. / p>     

risposta data 19.10.2012 - 20:23
fonte

Leggi altre domande sui tag