【问题标题】:ASP.NET MVC Software Design Pattern: DI,Repository,Service LayerASP.NET MVC 软件设计模式:DI、存储库、服务层
【发布时间】:2012-03-26 19:27:10
【问题描述】:

编辑

我应该将服务层和存储层放在一个项目中,以便 Web 项目能够引用 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 Music Store Tutorial 上做了一些阅读,然后是一本名为Pro ASP.NET MVC 3 Framework by Steven Sanderson (Apress) 的书,从书中我了解了DDD(域驱动设计)和其他一些概念,如存储库和依赖注入。跟着本书搭建了SportsStore网站,对DI有了一些基本的了解。但是我个人认为这个例子没有分离业务逻辑层,所以我研究了一下,发现了一个模式叫Service Layer Pattern,据我了解,它分离了业务逻辑层。基于此,我为我的新项目(示例项目如下)提出了一个结构。

我需要实现 IDisposable 接口吗?如果是,在哪里以及为什么? 这种结构对于比较大的项目是否可行?

示例数据库设计:Product(one)----(many)ProductCategoryRs(many)----(one)Category

该解决方案包含 3 个项目:Repository、Service、Web

存储库:

定义 IRepository 接口,基本的 CRUD 操作

这些签名是否足够?我应该添加 TEntity GetById(object id); 吗?

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

Web 项目,从服务中检索数据并转换为视图模型并显示。 产品控制器代码

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

【问题讨论】:

    标签: asp.net-mvc


    【解决方案1】:

    我相信您真的应该在您的 IRepository&lt;TEntity&gt; 通用接口中添加一个 TEntity GetById(int id)

    为什么?因为如果您不这样做,并且如果您想在业务层获取单个记录,那么您只有两个选择(在存储库、数据访问层):

    1. 返回一个完整的“unlazy”集合,这意味着您将返回 100,000 条记录以使用单个记录。
    2. 返回一个惰性集合,如IQueryable&lt;TEntity&gt;,是的,它可以让您从数据库中获取一条记录,但可能会导致很多nasty side-effects

    第一个选项显然是错误的。第二个是有争议的,但是(除非你的项目有你作为一个开发人员,并且你真的很清楚自己在做什么)它可能会泄漏和不安全。因此,如果您确实需要一条记录(有时您肯定会这样做),请公开一个可以做到这一点的方法。

    话虽如此,您也应该公开IQueryable&lt;TEntity&gt; All { get; },原因与上述完全相同。请改用IEnumerable&lt;TEntity&gt; All { get; },并通过例如调用context.Set&lt;TEntity&gt;().ToList() 使您的具体通用存储库类返回一个真实的集合。

    编辑

    关于 IDisposable:

    我能想到的实现 IDisposable 接口的原因只有两个(相关):

    1. 处置非托管资源
    2. implementing the RAII pattern 的酷炫方式。

    在您的情况下,您可能应该在您的存储库实现中使用它。请查看this SO question 了解更多信息。

    【讨论】:

    • -1,虽然您对 GetById 有很好的了解,但它并不是 OP 任何问题的答案。
    • @Levitikon:他询问了IDisposable,我回答了。这是 1 个答案(至少我是这样学会数数的,不确定你的情况:P)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-19
    • 2017-09-19
    • 1970-01-01
    • 1970-01-01
    • 2011-05-21
    相关资源
    最近更新 更多