Шаблон проектирования программного обеспечения ASP.NET MVC: DI, Repository, Service Layer - PullRequest
6 голосов
/ 09 марта 2012

РЕДАКТИРОВАТЬ

Должен ли я поместить сервисный слой и слой хранилища в один проект, чтобы веб-проект мог ссылаться на объекты DbContext?Теперь мой веб (контроллеры) не могут ссылаться на объекты dbcontext.Каков правильный путь?

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

Ниже приведен оригинальный вопрос

я знаю, что SO - отличное сообщество, чтобы публиковать мои вопросы о шаблонах проектирования mvc.Пожалуйста, дайте мне ваш совет, и я буду признателен за вашу помощь.Спасибо!

Мы планируем новый проект, и нашим приоритетом является разработка расширяемого и слабосвязанного приложения.

Я новичок в разработке программного обеспечения;Я прочитал Учебное пособие по музыкальному магазину MVC , а затем книгу Стивена Сандерсона (Apress) под названием Pro ASP.NET MVC 3 Framework. Из этой книги я узнал о DDD.(Доменное управление) и некоторые другие понятия, такие как репозиторий и внедрение зависимостей.Я следовал книге, чтобы создать сайт SportsStore, и получил некоторое общее представление о DI.Но я лично считаю, что этот пример не отделил слой бизнес-логики, поэтому я провел исследование по этому вопросу, обнаружил шаблон, называемый шаблоном уровня обслуживания, и, насколько я понимаю, он отделяет уровень бизнес-логики.Исходя из этого, я разработал структуру для моего нового проекта (пример проекта ниже).

Нужно ли реализовывать интерфейс IDisposable ?если да, то где и почему?Реальна ли эта структура для относительно крупномасштабного проекта?

Пример дизайна базы данных: Продукт (один) ---- (много) ProductCategoryRs (много) ---- (один) Категория

решение содержит 3 проекта: Репозиторий, Сервис, Интернет

Репозиторий:

Определение интерфейса IRepository, основные операции CRUD

Достаточно ли этих подписей?Должен ли я добавить TEntity GetById (идентификатор объекта); ?

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

Реализовать универсальный класс репозитория

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

Служба: определение интерфейса IProductService, расширение здесь бизнес-логики.

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

Реализация службы продукта

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

Веб-проект, получение данныхиз сервиса и конвертировать в viewmodel и отображать.Код продукта Controller

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

1 Ответ

2 голосов
/ 09 марта 2012

Я полагаю, вам действительно следует добавить TEntity GetById(int id) к вашему IRepository<TEntity> универсальному интерфейсу.

Почему?Потому что, если вы этого не сделаете, и если вы хотите получить одну запись на бизнес-уровне, у вас есть только два варианта (в хранилище, на уровне доступа к данным):

  1. Возврат завершен,"unlazy" collection означает, что вы вернете, скажем, 100 000 записей, чтобы использовать одну.
  2. Возвратите отложенную коллекцию, например IQueryable<TEntity>, которая, да, позволит вам получить однузапись из базы данных, но может вызвать множество неприятных побочных эффектов .

Первый вариант явно неверен.Второе противоречиво, но (если в вашем проекте вы не являетесь одним разработчиком, и вы действительно действительно знаете, что делаете), это потенциально утечка и небезопасно.Так что, если вам нужна единственная запись (а иногда и обязательно), предоставьте метод, который делает именно это.

Сказав это, вы также должны не выставить IQueryable<TEntity> All { get; } по тем же причинам, что и выше.Вместо этого используйте IEnumerable<TEntity> All { get; } и заставьте ваш конкретный универсальный класс репозитория возвращать реальную коллекцию, вызвав, например, context.Set<TEntity>().ToList().

Edit

Относительно IDisposable:

Есть только две (связанные) причины для реализации интерфейса IDisposable, о которых я могу думать:

  1. Удаление неуправляемых ресурсов
  2. Отличный способ реализацииШаблон RAII .

В вашем случае вы, вероятно, должны использовать его в своей реализации репозитория.Пожалуйста, посмотрите этот вопрос для получения дополнительной информации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...