ASP.NET MVC设计模式:DI,仓库,服务层 [英] ASP.NET MVC Software Design Pattern: DI,Repository,Service Layer
问题描述
修改
我应该把服务层和存储库层到一个项目,所以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方式>
泛型接口
为什么呢?因为如果你不这样做,如果你想你的业务层上取一个记录,你只有两个选择(对仓库,数据访问层):
- 返回一个完整的,unlazy集合,这意味着你会为了使用单一返回,说,10万条记录。
- 返回一个懒惰集合像
的IQueryable< TEntity>
,其中,是的,可以让你从数据库中获取单个记录,但可能会导致大量的<一个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接口,我能想到的:
- 处置非托管资源
- 实施的一个很酷的方式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):
- Return a complete, "unlazy" collection, meaning that you'll return, say, 100,000 records in order to use a single one.
- 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:
- Disposing unmanaged resources
- 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屋!