2012-03-09 19 views
5

EDITASP.NET MVC Software Design Pattern: DI, Repository, Service Layer

Devo mettere livello di servizio e lo strato repository in un unico progetto, in modo che il progetto web è in grado di fare riferimento a oggetti DbContext? Ora il mio web (controller) non è in grado di fare riferimento agli oggetti dbcontext. qual è la strada giusta?

// service and repository are together 
(View <- Controller) -> (Service -> Repository -> EF DbContext) -> (DB) 
// separate service and repository layer 
(View <- Controller) -> (Service) -> (Repository -> EF DbContext) -> (DB) 

Qui di seguito sono domanda iniziale

che conosco così è una comunità eccellente per pubblicare le mie domande su design pattern MVC. Per favore, dammi il tuo consiglio e apprezzerò il tuo aiuto. Grazie!

Stiamo pianificando un nuovo progetto e la nostra priorità è sviluppare un'applicazione estensibile e liberamente accoppiata.

Sono nuovo nello sviluppo di software; Ho fatto qualche lettura su MVC Music Store Tutorial e seguito da un libro chiamato Pro ASP.NET MVC 3 Framework by Steven Sanderson (Apress), dal libro, ho imparato a conoscere DDD (Domain driven design) e alcuni altri concetti come l'iniezione di repository e dipendenza. Ho seguito il libro per costruire il sito Web di SportsStore e ho acquisito alcune nozioni di base su DI. Ma personalmente penso che l'esempio non abbia separato il livello della logica aziendale, quindi ho fatto una ricerca al riguardo, ho trovato un modello chiamato Service Layer Pattern e, da quello che ho capito, separa il livello della logica aziendale. Sulla base di questo, sono uscito con una struttura per il mio nuovo progetto (progetto di esempio sotto).

Devo implementare l'interfaccia IDisposable? se sì, dove e perché? Questa struttura è fattibile per un progetto relativamente grande?

campione progettazione di database: del prodotto (uno) ---- (molti) ProductCategoryRs (molti) ---- (uno) Categoria

la soluzione contiene 3 progetti: Repository, Servizio, web

Repository:

definire interfaccia IRepository, operazioni CRUD

Queste firme sono sufficienti? Devo aggiungere TEntity GetById (id oggetto);?

public interface IRepository<TEntity> 
{ 
    IQueryable<TEntity> All { get; } 
    void Create(TEntity item); 
    void Update(TEntity item); 
    void Delete(TEntity item); 
    void SaveChanges(); 
} 

Implementare generica classe repository

public class Repository<TEntity> : IRepository<TEntity> where TEntity : class 
{ 
    STOREEntities context; 
    public Repository() 
    { 
     context = new STOREEntities(); 
    } 
    public IQueryable<TEntity> All 
    { 
     get 
     { 
      return context.Set<TEntity>(); 
     } 
    } 
    public void Create(TEntity item) 
    { 
     context.Set<TEntity>().Add(item); 
    } 
    public void Update(TEntity item) 
    { 
     context.Entry<TEntity>(item).State = System.Data.EntityState.Modified; 
    } 
    public void Delete(TEntity item) 
    { 
     context.Set<TEntity>().Remove(item); 
    } 
    public void SaveChanges() 
    { 
     context.SaveChanges(); 
    } 
} 

Servizio: Definire l'interfaccia IProductService, estendere la logica di business qui.

public interface IProductService 
{ 
    IEnumerable<Product> Products { get; } 
    IEnumerable<Product> Get(Expression<Func<Product, Boolean>> filter); 
    Product GetByProductId(int productId); 
    void AddProduct(Product product); 
    void EditProduct(Product product); 
    void RemoveProduct(Product product); 
    void SaveChanges(); 
} 

Implementare progetto Web Product Service

public class ProductService : IProductService 
{ 
    IRepository<Product> repository; //Inject 
    public ProductService(IRepository<Product> repo) 
    { 
     repository = repo; 
    } 
    public IEnumerable<Product> Products 
    { 
     get { return repository.All; } 
    } 
    public IEnumerable<Product> Get(Expression<Func<Product, bool>> filter) 
    { 
     return repository.All.Where(filter); 
    } 
    public Product GetByProductId(int productId) 
    { 
     return repository.All.SingleOrDefault(p => p.ProductID == productId); 
    } 
    public void AddProduct(Product product) 
    { 
     repository.Create(product); 
    } 
    public void EditProduct(Product product) 
    { 
     repository.Update(product); 
    } 
    public void RemoveProduct(Product product) 
    { 
     repository.Delete(product); 
    } 
    public void SaveChanges() 
    { 
     repository.SaveChanges(); 
    } 
} 

, recuperare i dati da un servizio e convertire in ViewModel e visualizzazione. codice ProductController

public class ProductController : Controller 
{ 
    IProductService productService; //inject 
    public ProductController(IProductService service) 
    { 
     productService = service; 
    } 
    public ActionResult Index() 
    { 
     var products = productService.Products; //retrieve from service layer 
     return View(products); 
    } 
} 

risposta

2

Credo che si dovrebbe davvero aggiungere un TEntity GetById(int id) alla vostra interfaccia generica IRepository<TEntity>.

Perché? Perché se non lo fai, e se si vuole recuperare un singolo record sul vostro livello di business, si hanno solo due opzioni (sul repository, lo strato di accesso ai dati):

  1. restituiscono un completo, "unlazy" collezione, nel senso che restituirai, diciamo, 100.000 record per poterne utilizzare uno solo.
  2. Restituisce una raccolta lenta come IQueryable<TEntity>, che, sì, consente di ottenere un singolo record dal database, ma potrebbe causare molto nasty side-effects.

La prima opzione è chiaramente errata. Il secondo è controverso, ma (a meno che il tuo progetto non abbia te come unico sviluppatore e tu davvero sai davvero cosa stai facendo) è potenzialmente dispersivo e pericoloso. Quindi, se hai bisogno di un singolo record (e qualche volta lo farai sicuramente), esponi un metodo che fa esattamente questo.

Detto questo, si dovrebbe anche non esporre IQueryable<TEntity> All { get; }, esattamente per gli stessi motivi sopra. Utilizzare invece IEnumerable<TEntity> All { get; } e fare in modo che la classe di repository generica concreta restituisca una raccolta reale, chiamando ad esempio context.Set<TEntity>().ToList().

Modifica

Per quanto riguarda IDisposable:

Ci sono solo due (oggetti legati) ragioni per implementare l'interfaccia IDisposable che mi viene in mente:

  1. Smaltimento risorse non gestite
  2. A cool way of implementing the RAII pattern.

Nel tuo caso, probabilmente dovresti usare nell'implementazione del tuo repository. Si prega di dare un'occhiata a this SO question per ulteriori informazioni.

+0

@null: modificherò la mia risposta, per favore dai un'occhiata. – rsenna

+0

-1, Sebbene tu abbia una buona conoscenza di GetById, non è stata la risposta a nessuna delle domande dell'OP. – Levitikon

+1

@Levitikon: ha chiesto di "IDisposable" e io ho risposto. Questa è una risposta (almeno è così che ho imparato a contare, non sono sicuro di te: P) – rsenna