2010-11-09 6 views
5

Vorrei implementare la tipica architettura a tre strati. Il mio attuale approccio appare come segueDomanda di progetto oggetti POCO/accesso DAL

  • DAL - con EF 4.0 e repository per ciascuna delle mie entità. accesso attraverso le interfacce
  • Stavo pensando di utilizzare oggetti POCO. La mia prima domanda sarebbe dove dovrei mettere quei file ? In un assembly a cui fanno riferimento tutti gli altri progetti?
  • BLL - Come ottengo i dati dal DAL al BLL e infine alla GUI È un buon modo se avessi un sacco di classi di manager come CustomerManager nella BLL. Queste classi dovrebbero accedere al repository corrispondente nella BLL e poi passare gli oggetti per l'interfaccia grafica

o pensi che è meglio mettere il repository nel BLL e accedervi direttamente dal dire la mia ButtonEventHandler?

Speriamo che si può portare un po 'di luce nel buio

+0

Se una delle nostre risposte ha aiutato, contrassegnarlo come accettato – Basic

risposta

6

Abbiamo i pronti contro termine nel DAL. La BLL fa riferimento ai repository tramite un'interfaccia - quindi i repository sono legati al DAL ma disaccoppiati dalla BLL. Non conosco alcuna ragione per cui i repository non potrebbero essere direttamente nella BLL. Li abbiamo nel DAL perché non mettiamo in loro alcuna logica. Abbiamo quindi "Manager" nella BLL che avvolgono i repository e gestiscono la logica specifica dell'entità.

FWIW abbiamo effettivamente un Repository(Of IEntity) generico e utilizzare l'unità per istanziare il repository appropriato come richiesto: è molto compatto e abbastanza elegante. Tutte le nostre entità POCO implementano IEntity che contiene Id, CreatedDate, ecc. Che sono comuni a TUTTE le nostre entità. Questo dà alcuni altri benefici quando si ha bisogno di gestire qualsiasi tipo di entità genericamente - CreatedDate è impostato dal repository quando CreateInstance() si chiama, ModifiedDate è impostato dal contesto stesso quando si impegna un'entità con uno stato di Modified

Manteniamo entità in un progetto separato - Il DAL deve essere in grado di farvi riferimento, così come il BLL. Non li vuoi nel DAL, in quanto lo scambio di DAL out causerebbe problemi. Non puoi metterli nella BLL o ottieni un riferimento circolare. La configurazione per le entità può essere inclusa nel DAL in quanto specifica per origine dati.

Cerchiamo di attenerci al BLL che acquisisce primitive e restituisce entità. Fai attenzione a tenere le entità nell'interfaccia utente troppo a lungo, soprattutto in un'app Web, poiché potresti avere un contesto diverso sotto il DAL quando restituisci l'entità alla BLL per l'elaborazione (ossia tra le richieste archiviate in sessione o simili). può risultare in tutti i tipi di divertimento attaccare/separare le entità dai contesti e perdere alcuni benefici come il rilevamento delle modifiche.

Speranza che aiuta, ma se volete qualsiasi chiarimento, fatemi sapere

+0

Grazie per la risposta. Le tue lezioni di manager sono statiche? – Developer23

+0

In realtà no, usiamo ancora l'injection unità/dipendenza per restituire un riferimento a una singola istanza. Questo perché i manager dipendono da repository che a loro volta dipendono dal contesto che non è statico. Probabilmente potresti aggirare questo problema ma non lo abbiamo fatto. – Basic

+0

Ancora una domanda banale. Qual è la tua raccomandazione in termini di denominazione. Usi qualcosa come CustomerManager o come RPM1984 ha scritto CustomerService? – Developer23

1

È possibile mantenere questo molto semplice da mantenere i vostri repository e pocos nello stesso progetto. Questo sarebbe essenzialmente il tuo modello di dominio dei dati. I tuoi POCO sono pubblici e anche le interfacce del tuo repository. Dovresti mantenere i tuoi repository concreti interni a questo progetto.

Il BLL potrebbe essere una facciata classica o un localizzatore di servizi. Questo progetto avrebbe massaggiato i tuoi dati e applicato tutte le regole aziendali pertinenti prima di passarle all'interfaccia utente. Ciò sarebbe anche responsabile della convalida dei dati provenienti dall'interfaccia utente prima di inviarli al DAL.

+0

Approccio interessante. Dove vive la configurazione dell'entità? cioè i tipi di dati SQL per proprietà, indici? – Basic

+0

Non sono sicuro di aver compreso correttamente la tua domanda. Tutti gli accessi a SQL verranno estratti dal tuo modello di dati (.edmx). – Praveen

+0

Ah okay - Utilizziamo EF4 code-first in modo che le nostre entità siano classi che creiamo a mano e modifichiamo manualmente le nostre configurazioni (chiavi, FK, ecc.) Questo significa che possiamo mantenere le cose specifiche di SQL come i tipi di dati legati al DAL ma hanno le entità POCO generiche. – Basic

3

Questa è la nostra messa a punto:

Company.Project.Domain.Model  (POCOs) 
Company.Project.Business.Services (BLL) 
Company.Project.Data.Repositories (Repository) 
Company.Project.Web    (Presentation) 
  • POCO'S sono nel loro assemblaggio. Nessun riferimento e Riferimento a tutti.
  • BLL esegue query su repository, applica regole aziendali e idratazione. Resi ICollection<T> o T. Riferimenti repository (tramite interfaccia generica IRepository<T>) e POCO.
  • Il repository è un insieme di classi generiche che implementano IRepository<T> per fornire una persistenza di base rispetto all'archivio sottostante. Trova, aggiungi, rimuovi, ecc. Restituisce IQueryable. Riferimenti POCO, Riferimento a BLL.
  • Presentazione è l'interfaccia utente. Riferimenti POCO e BLL.

Il risultato finale è un approccio simile allo stack e poiché fondamentalmente tutto avviene tramite interfacce (e registri DI), la flessibilità è enorme.

Abbiamo depositi fittizi che vengono iniettati nei progetti di test tramite DI e i repository di Entity Framework che vengono iniettati nella BLL tramite DI.

flusso Esempio da UI -> DB:

// "Company.Project.Web.ProductsController.cs" 
public class ProductsController : BaseController 
{ 
    private IProductService _productService; 

    public ProductsController(IProductService productService) 
    { 
     this._productService = productService; // DI makes me happy :) 
    } 

    public ActionResult GetOrdersForProduct(Product product) 
    { 
     var orders = _productService.GetOrders(product); 
     return View(orders); 
    } 
} 

// "Company.Project.Business.Services.ProductService.cs" 
public class ProductService : IProductService 
{ 
    private IRepository<Product> _productRepository; 

    public ProductService (IRepository<Product> productRepository) 
    { 
     this._productRepository = productRepository; // DI makes me happy :) 
    } 

    public ICollection<Orders> GetOrdersForProduct(Product product) 
    { 
     return _productRepository 
       .Find() 
       .ForProduct(product) // IQueryable<Product> pipe/extension filter 
       .ToList(); 
    } 
} 

// "Company.Project.Data.Repositories.GenericRepository.cs 
public class GenericRepository<T> : IRepository<T> where T : class 
{ 
    private IObjectSet<T> _objectSet; 

    public GenericRepository(IUnitOfWork unitOfWork) 
    { 
     CurrentContext = unitOfWork as SqlServerUnitOfWork; 
    } 

    public IQueryable<T> Find() 
    { 
     return CurrentContext.GetEntitySet<T>(); 
    } 

    protected SqlServerUnitOfWork CurrentContext { get; private set; } 

    protected IObjectSet<T> CurrentEntitySet 
    { 
     // some plularization smarts in "SqlServerUnitofWork.cs", to dynamically pull 
     // back entity set based on T. 
     get { return _objectSet ?? (_objectSet = CurrentContext.GetEntitySet<T>()); } 
    } 
} 

Come potete vedere, io sono un fanboy DI.

+1

Solo un suggerimento sul rendimento - Invece di restituire ICollection provare a restituire IQueryable - Ciò consente a Lazy di caricare gli elementi nell'elenco riducendo l'overhead se l'interfaccia utente ha solo bisogno di sottoinsieme (ad esempio per il paging) – Basic

+0

@Basiclife - leggi la mia parte sul repository. Sto facendo esattamente questo. IMO dovrebbero essere posticipati alla BLL, non più in basso all'interfaccia utente, altrimenti si potrebbero ottenere risultati imprevisti. Il paging è facile, basta passare il pagenumber/pagesize al metodo nella BLL, che salta/assume l'iqueryable dal repository. – RPM1984

+0

E a proposito, non è un caricamento pigro, cioè ** esecuzione differita **. Stai attento a non confondere i due. Disattivo il caricamento lento in EF e carico le entità che BLL richiede usando '.Include'. – RPM1984