ASP.NET MVC设计模式:DI,仓库,服务层 [英] ASP.NET MVC Software Design Pattern: DI,Repository,Service Layer

查看:213
本文介绍了ASP.NET MVC设计模式:DI,仓库,服务层的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

修改

我应该把服务层和存储库层到一个项目,所以web项目能够参考的DbContext对象?现在我的网站(控制器)无法参考的DbContext对象。什么是正确的方法是什么?

  //服务和存储库在一起
(查看< - 控制器) - GT; (服务 - >库 - > EF的DbContext) - GT; (DB)
//单独的服务和存储库层
(查看< - 控制器) - GT; (服务) - GT; (库 - > EF的DbContext) - GT; (DB)

下面是原题

我知道,所以是一个很好的社区张贴我对MVC设计模式的问题。请给我你的建议,我将AP preciate你的帮助。谢谢!

我们正在规划一个新的项目,我们的首要任务是开发一个应用程序,扩展性和松耦合。

我是新软件的开发;我做了 MVC音乐商店教程一些阅读以及随后称为临ASP.NET MVC 3框架(一本由史蒂芬·桑德森一preSS),从本书中,我学到了DDD(领域驱动设计)和其他一些概念,如存储库和依赖注入。我按照书建SportsStore网站,并获得了约DI一些基本的了解。但是,我个人认为这个例子没有业务逻辑层中分离出来,所以我做了一个研究,我发现了一个叫做服务层图案模式,从我的理解,它业务逻辑层分离。在此基础上,我来到了一个结构,我的新项目(以下示例项目)。

我是否需要实施的IDisposable 界面?如果是的话,在那里,为什么?
这是结构一个比较大的规模的项目是否可行?

样本数据库设计:产品(一个)----(多)ProductCategoryRs(很多)----(一个)类别

解决方案包含3个项目:仓库,服务,网络

存储库:

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

是这些签名是否足够?我要补充的 TEntity GetById(对象ID);

 公共接口IRepository< TEntity>
{
    IQueryable的< TEntity>所有{搞定; }
    void创建(TEntity项目);
    无效更新(TEntity项目);
    无效删除(TEntity项目);
    无效的SaveChanges();
}

实现通用库类

 公共类资源库< TEntity> :IRepository< TEntity>其中,TEntity:类
{
    STOREEntities背景;
    公共库()
    {
        上下文=新STOREEntities();
    }
    公众的IQueryable< TEntity>所有
    {
        得到
        {
            返回context.Set< TEntity>();
        }
    }
    公共无效创建(TEntity项)
    {
        context.Set< TEntity>()添加(项目)。
    }
    公共无效更新(TEntity项)
    {
        context.Entry< TEntity>(项目)= .STATE System.Data.EntityState.Modified;
    }
    公共无效删除(TEntity项)
    {
        context.Set< TEntity>()删除(项目)。
    }
    公共无效的SaveChanges()
    {
        context.SaveChanges();
    }
}

服务:
定义IProductService界面,在这里扩展业务逻辑。

 公共接口IProductService
{
    IEnumerable的<产品与GT;产品{搞定; }
    IEnumerable的<产品与GT;获取(前pression<&Func键LT;产品,布尔>>过滤器);
    产品GetByProductId(INT的productId);
    无效addProduct命令(产品产品);
    无效EditProduct(产品产品);
    无效RemoveProduct(产品产品);
    无效的SaveChanges();
}

实施产品服务

 公共类ProductService:IProductService
{
    IRepository<产品与GT;库; //注入
    公共ProductService(IRepository<产品与GT;回购)
    {
        库=回购;
    }
    公共IEnumerable的<产品与GT;制品
    {
        {返回repository.All; }
    }
    公共IEnumerable的<产品与GT;获取(前pression<&Func键LT;产品,布尔>>过滤器)
    {
        返回repository.All.Where(过滤器);
    }
    公共产品GetByProductId(INT的productId)
    {
        返回repository.All.SingleOrDefault(P => p.ProductID ==的productId);
    }
    公共无效addProduct命令(产品产品)
    {
        repository.Create(产品);
    }
    公共无效EditProduct(产品产品)
    {
        repository.Update(产品);
    }
    公共无效RemoveProduct(产品产品)
    {
        repository.Delete(产品);
    }
    公共无效的SaveChanges()
    {
        repository.SaveChanges();
    }
}

Web项目,检索服务数据,并转换为视图模型和显示。
ProductController的code

 公共类ProductController的:控制器
{
    IProductService productService; //注入
    公共ProductController的(IProductService服务)
    {
        productService =服务;
    }
    公众的ActionResult指数()
    {
        变种产品= productService.Products; //从服务层检索
        返回查看(产品);
    }
}


解决方案

我相信你的真的应该添加 TEntity GetById(INT ID)你的 IRepository< TEntity方式> 泛型接口

为什么呢?因为如果你不这样做,如果你想你的业务层上取一个记录,你只有两个选择(对仓库,数据访问层):


  1. 返回一个完整的,unlazy集合,这意味着你会为了使用单一返回,说,10万条记录。

  2. 返回一个懒惰集合像的IQueryable&LT; TEntity&GT; ,其中,是的,可以让你从数据库中获取单个记录,但可能会导致大量的<一个href=\"http://www.weirdlover.com/2010/05/11/iqueryable-can-kill-your-dog-steal-your-wife-kill-your-will-to-live-etc/\"相对=nofollow>讨厌的副作用。

第一种选择显然是错误的。二是有争议的,但(除非你的项目有你作为一个开发者,你真的真的真的知道自己在做什么),这是潜在的泄漏,不安全。所以,如果你确实需要一个记录(有时你肯定会这么做),揭露了正是这么做的方法。

说了这么多,你也应该的不可以公开的IQueryable&LT; TEntity&GT;所有{搞定; } ,整整上述同样的原因。使用的IEnumerable&LT; TEntity&GT;所有{搞定; } 来代替,让你的具体泛型仓储类返回一个真正的集合,通过调用 context.Set&LT; TEntity方式&gt;()了ToList()的实例。

修改

关于IDisposable的:

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


  1. 处置非托管资源

  2. 实施的一个很酷的方式RAII模式

在你的情况,你可能的用它在你的仓库实现。请看看<一个href=\"http://stackoverflow.com/questions/2975760/should-linq-to-sql-repository-implement-idisposable\">this SO质疑了解更多信息。

EDIT

Should i put service layer and repository layer into one project, so the web project is able to reference to DbContext objects ? Now my web(controllers) are unable to reference to dbcontext objects. what is the right way?

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

Below are original question

i know SO is an excellent community to post my questions about mvc design patterns. Please give me your advice and I will appreciate your help. Thank you!

We are planning for a new project and our priority is to develop an application that is extensible and loosely-coupled.

I am new to software development; I did some reading on MVC Music Store Tutorial, and followed by a book called Pro ASP.NET MVC 3 Framework by Steven Sanderson (Apress),From the book, I learnt about DDD(Domain driven design) and some other concepts like repository and dependency injection. I have followed the book to build the SportsStore website, and gained some basic understanding about DI. But I personally think that the example did not separate the business logic layer, so i did a research on that, i found a pattern called Service Layer Pattern, and from what i understand, it separates the Business logic layer. Based on this, I came out with a structure for my new project(sample project below).

Do i need to implement IDisposable interface? if yes, where and why? Is this structure feasible for a relatively big-scale project?

sample database design: Product(one)----(many)ProductCategoryRs(many)----(one)Category

the solution contains 3 projects: Repository,Service,Web

Repository:

Define IRepository interface , basic CRUD operations

Are these signatures sufficient? Should I add 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();
}

Implement generic Repository class

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

Service: Define IProductService interface, extend business logic here.

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

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

Web project, retrieve data from service and convert to viewmodel and display. ProductController code

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

解决方案

I believe you really should add a TEntity GetById(int id) to your IRepository<TEntity> generic interface.

Why? Because if you don't, and if you want to fetch a single record on your business layer, you only have two options (on the repository, data-access layer):

  1. Return a complete, "unlazy" collection, meaning that you'll return, say, 100,000 records in order to use a single one.
  2. Return a lazy collection like IQueryable<TEntity>, which, yes, will allow you to get a single record from the database, but may cause a lot of nasty side-effects.

The first option is clearly wrong. The second is controversial, but (unless your project has you as a single developer, and you really really really know what you're doing) it is potentially leaky and unsafe. So, if you do need a single record (and sometimes you'll surely do), expose a method that does exactly that.

Having said that, you should also not expose IQueryable<TEntity> All { get; }, for exactly the same reasons above. Use IEnumerable<TEntity> All { get; } instead, and make your concrete generic repository class return a real collection, by calling context.Set<TEntity>().ToList() for instance.

Edit

Regarding IDisposable:

There are only two (related) reasons for implementing the IDisposable interface that I can think of:

  1. Disposing unmanaged resources
  2. A cool way of implementing the RAII pattern.

In your case, you probably should use it on your repository implementation. Please take a look at this SO question for further information.

这篇关于ASP.NET MVC设计模式:DI,仓库,服务层的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆