EF UoC
The Repository Pattern with EF Code First & Dependency Injection in ASP.NET MVC3

Ray_Liang, 5 Jul 2011 GPL3
156.8K
8.1K
156
|
|
4.65 (58 votes) |
|
1 |
2 |
3 |
4 |
5 |
4.65/5 - 58 votes
3 removed
μ 4.53, σa 1.20 [?]
Add a reason or comment to your vote: x
Adding a comment to your rating is optional
In this article, I will explain how to implement Respository pattern with EF4.1 code first and how to enable dependency injection feature to your ASP.NET MVC3 Applications.
Introduction
These days, I started using EF code first and thought about how could I take advantage from it for my recent project. My project is based on MVC3 and there are some challenges to continue updating this project. At that time, I must finish my job in a very short deadline so fast so good I just define some data access interfaces and implemented them with EF4.
There are some things in my project troubling me:
I have used the EF entities in my controllers anywhere that there is a connection translation error throwing infrequently.
Modules coupling degree becoming closed.
Manage services and contexts life cycle are difficult.
Obviously, it needs to refactor my project with a new architecture designing.
Preparing
Before starting my work, I need to do some researching and learning. I have read a large numbers of articles about DDD, SOA, EF code first, Dependency Injection pattern, Repository pattern even watch all web casts about MVC on ASP.NET and a week later...
I have really found some useful resources about those topics and I am sharing them below:
ASP.NET MVC Storefront Starter Kit videos
Repository Pattern- by Martin fowler
A dependency injection library for .NET
"ASP.NET MVC 3 Service Location" - by Brad Wilson
Modeling
At first, I need to create the data model classes (the POCO objects) for this demo I will create Category and Product.
Hide Shrink
Copy Code
namespace Demo.DAL
{
public class Category
{
[Key]
public int ID { get; set; }
public virtual string Name { get; set; }
public virtual string Title { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class Product
{
[Key]
public int ID { get; set; }
public int CategoryID { get; set; }
[ForeignKey("CategoryID")]
public virtual Category Category {get;set;}
public string Name { get; set; }
public string Title { get; set; }
public string Description{get;set;}
public decimal Price { get; set; }
}
public class DB : DbContext
{
public DB() : base("DemoDB") { }
public DbSet<Category> Categories { get; set; }
public DbSet<Product> Products { get; set; }
}
}

Repository Pattern with EF Code First
When I finish my learning on EF code first and Repository, I couldn't find any solutions for implementing Repository pattern with EF code first. EF4.1 is so powerful for building the DAL that it allows us to use POCO objects to define our database and BO (business objects) instead of inheriting from Entity that could give me a big hand. I could very easily define the repository interface like below:
Hide Shrink
Copy Code
public interface IRepository<T>: IDisposable where T : class
{
/// <summary>
/// Gets all objects from database
/// </summary>
IQueryable<T> All();
/// <summary>
/// Gets objects from database by filter.
/// </summary>
/// <param name="predicate">Specified a filter</param>
IQueryable<T> Filter(Expression<Func<T, bool>> predicate);
/// <summary>
/// Gets objects from database with filting and paging.
/// </summary>
/// <typeparam name="Key"></typeparam>
/// <param name="filter">Specified a filter</param>
/// <param name="total">Returns the total records count of the filter.</param>
/// <param name="index">Specified the page index.</param>
/// <param name="size">Specified the page size</param>
IQueryable<T> Filter<Key>(Expression<Func<T, bool>> filter ,
out int total, int index = 0, int size = 50);
/// <summary>
/// Gets the object(s) is exists in database by specified filter.
/// </summary>
/// <param name="predicate">Specified the filter expression</param>
bool Contains(Expression<Func<T, bool>> predicate);
/// <summary>
/// Find object by keys.
/// </summary>
/// <param name="keys">Specified the search keys.</param>
T Find(params object[] keys);
/// <summary>
/// Find object by specified expression.
/// </summary>
/// <param name="predicate"></param>
T Find(Expression<Func<T, bool>> predicate);
/// <summary>
/// Create a new object to database.
/// </summary>
/// <param name="t">Specified a new object to create.</param>
T Create(T t);
/// <summary>
/// Delete the object from database.
/// </summary>
/// <param name="t">Specified a existing object to delete.</param>
void Delete(T t);
/// <summary>
/// Delete objects from database by specified filter expression.
/// </summary>
/// <param name="predicate"></param>
int Delete(Expression<Func<T, bool>> predicate);
/// <summary>
/// Update object changes and save to database.
/// </summary>
/// <param name="t">Specified the object to save.</param>
int Update(T t);
/// <summary>
/// Get the total objects count.
/// </summary>
int Count { get; }
}
Now create a general repository for EF code first that implement the IRepository:
Hide Shrink
Copy Code
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Data.Entity;
using System.Collections.Generic;
using System.Data;
namespace Demo.DAL
{
public class Repository<TObject> : IRepository<TObject>
where TObject : class
{
protected DB Context;
protected DB Context = null;
private bool shareContext = false;
public Repository()
{
Context = new DB();
}
public Repository(DB context)
{
Context = context;
shareContext = true;
}
protected DbSet<TObject> DbSet
{
get
{
return Context.Set<TObject>();
}
}
public void Dispose()
{
if (shareContext && (Context != null))
Context.Dispose();
}
public virtual IQueryable<TObject> All()
{
return DbSet.AsQueryable();
}
public virtual IQueryable<TObject>
Filter(Expression<Func<TObject, bool>> predicate)
{
return DbSet.Where(predicate).AsQueryable<TObject>();
}
public virtual IQueryable<TObject> Filter(Expression<Func<TObject, bool>> filter,
out int total, int index = 0, int size = 50)
{
int skipCount = index * size;
var _resetSet = filter != null ? DbSet.Where(filter).AsQueryable() :
DbSet.AsQueryable();
_resetSet = skipCount == 0 ? _resetSet.Take(size) :
_resetSet.Skip(skipCount).Take(size);
total = _resetSet.Count();
return _resetSet.AsQueryable();
}
public bool Contains(Expression<Func<TObject, bool>> predicate)
{
return DbSet.Count(predicate) > 0;
}
public virtual TObject Find(params object[] keys)
{
return DbSet.Find(keys);
}
public virtual TObject Find(Expression<Func<TObject, bool>> predicate)
{
return DbSet.FirstOrDefault(predicate);
}
public virtual TObject Create(TObject TObject)
{
var newEntry = DbSet.Add(TObject);
if (!shareContext)
Context.SaveChanges();
return newEntry;
}
public virtual int Count
{
get
{
return DbSet.Count();
}
}
public virtual int Delete(TObject TObject)
{
DbSet.Remove(TObject);
if (!shareContext)
return Context.SaveChanges();
return 0;
}
public virtual int Update(TObject TObject)
{
var entry = Context.Entry(TObject);
DbSet.Attach(TObject);
entry.State = EntityState.Modified;
if (!shareContext)
return Context.SaveChanges();
return 0;
}
public virtual int Delete(Expression<Func<TObject, bool>> predicate)
{
var objects = Filter(predicate);
foreach (var obj in objects)
DbSet.Remove(obj);
if (!shareContext)
return Context.SaveChanges();
return 0;
}
}
}
The Repository has two running modes: exclusive mode and shared mode.
Exclusive mode: The data context is generated by Repository, the data objects only use in the Repository's data context (Update, Delete).
Shared mode: In many scenarios, we maybe use over 1 repository at the same time. If repositories have their own data context, it may cause the data duplicate issue. So we need to pass the shared data context to repositories in transaction on construction.
To make this example more close to a reality project, I have defined two repository interfaces for Category and Product.
Hide Shrink
Copy Code
public interface ICategoryRepository:IRepository<Category>
{
string GetUrl();
}
public interface IProductRepository : IRepository<Product>
{
string ResolvePicture();
}
public class CategoryRepository : Repository<Category>, ICategoryRepository
{
public CategoryRepository(DB context) : base(context) { }
public string GetUrl()
{
return "";
}
}
public class ProductRepostiroy : Repository<Product>, IProductRepository
{
public ProductRepostiroy(DB context) : base(context) { }
public string ResolvePicture()
{
return "";
}
}
In order to share data context, I use the UnitOfWork design pattern to maintain the data context and interoperability repository life time.
UnitOfWork Pattern
According to Martin Fowler, the Unit of Work pattern "maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems."
We could implement the UnitOfWork pattern in two ways:
Implement a GeneralRepository<T> class and embed in UnitOfWork. Then define the wapper methods and expose them to invoke the GeneralRepository<T>. But I don't think it's the best way, because the UnitOfWork will become very common and I couldn't use any subclass of Repository.
Inject the IRepository descendant interfaces into UnitOfWork.
Hide Copy Code
public interface IUnitOfWork:IDisposable
{
int SaveChanges();
}
public interface IDALContext : IUnitOfWork
{
ICategoryRepository Categories { get; }
IProductRepository Products { get; }
}
IUnitOfWork interface is very simple, it is only used to save changes, the IDALContext is use to define the IRepository descendant interfaces, construct and maintain the data context and Repository classes.
Hide Shrink
Copy Code
public class DALContext : IDALContext
{
private DB dbContext;
private ICategoryRepository categories;
private IProductRepository products;
public DALContext()
{
dbContext = new DB();
}
public ICategoryRepository Categories
{
get
{
if (categories == null)
categories = new CategoryRepository(dbContext);
return categories;
}
}
public IProductRepository Products
{
get
{
if (products == null)
products = new ProductRepostiroy(dbContext);
return products;
}
}
public int SaveChanges()
{
throw new NotImplementedException();
}
public void Dispose()
{
if (categories != null)
categories.Dispose();
if (products != null)
products.Dispose();
if (dbContext != null)
dbContext.Dispose();
GC.SuppressFinalize(this);
}
}
Service Layer
The DAL has been done! Constantly we need to create the SL (Service Layer). Now I create a new service interface to get categories, products or create new product.
Through the service layer, used to encapsulate data level of implementation details, call to the interface should be designed to be simple as possible. Service layer is usually called by the Controller in the MVC, Controller only needs to use the service interface, and the DI is responsible for construction, such a Controller and data layer of coupling is greatly reduced.
Hide Shrink
Copy Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.Practices.Unity;
using Demo.DAL;
namespace Demo.Services
{
public interface ICatalogService
{
List<Category> GetCategories();
List<Product> GetProducts();
Product CreateProduct(string categoryName, string productName, int price);
}
public class CatalogService : ICatalogService, IDisposable
{
private IDALContext context;
public CatalogService(IDALContext dal)
{
context = dal;
}
public List<Category> GetCategories()
{
return context.Categories.All().ToList();
}
public List<Product> GetProducts()
{
return context.Products.All().ToList();
}
public Product CreateProduct(string categoryName, string productName, int price)
{
var category = new Category() { Name = categoryName };
var product = new Product()
{ Name=productName,Price=price,Category=category };
context.Products.Create(product);
context.SaveChanges();
return product;
}
public void Dispose()
{
if (context != null)
context.Dispose();
}
}
}
Controller
Pass the ICatalogService instance to controller by used construction injection.
Hide Copy Code
public class HomeController : Controller
{
private ICatalogService service;
public HomeController(ICatalogService srv)
{
service = srv;
}
public ActionResult Index()
{
ViewData.Model = service.GetCategories();
return View();
}
}
OK, that is what I want. Finally, we need to construct and "Inject" instances to this object model.
Dependency Injection in MVC3
In MVC3, we could use the DependencyResolver.SetResolver(IDependencyResolver resolver) to register a Dependency Injection Container and use IDependencyResolver.GetService() method to locate our registered service instance that is a very amazing feature in this version. For more about DI in MVC3, you could read the "ASP.NET MVC 3 Service Location" below.
I have read that many developers like to create a new ControllerFactory to inject the controller instance. Actually that is not necessary! Because the MVC3 will call DependencyResolver.GetService to construe the Controller, so I only need to do one thing: Implement the IDependencyResolver.
Unity
We could found many popular DI framework in Google such as Castle Windsor, Structuremap,ObjectBuilder, Managed Extensibility Framework (MEF) and Microsoft Unity, I'd like to use Microsoft Unity 2.0 because the MVC DI features in comes from it that means we could very easy to implement DI in our MVC applications.
References from MSDN:
Unity is a lightweight, extensible dependency injection container that supports interception, constructor injection, property injection, and method call injection. You can use Unity in a variety of different ways to help decouple the components of your applications, to maximize coherence in components, and to simplify design, implementation, testing, and administration of these applications.
Unity is a general-purpose container for use in any type of Microsoft® .NET Framework-based application. It provides all of the features commonly found in dependency injection mechanisms, including methods to register type mappings and object instances, resolve objects, manage object lifetimes, and inject dependent objects into the parameters of constructors and methods and as the value of properties of objects it resolves.
In addition,
Unity is extensible. You can write container extensions that change the behavior of the container, or add new capabilities. For example, the interception feature provided by Unity, which you can use to add policies to objects, is implemented as a container extension.
Implement IDependencyResolver
The next step is create a DependencyResolver for MVC:
Hide Shrink
Copy Code
namespace Demo.Web
{
public class UnityDependencyResolver : IDependencyResolver
{
readonly IUnityContainer _container;
public UnityDependencyResolver(IUnityContainer container)
{
this._container = container;
}
public object GetService(Type serviceType)
{
try
{
return _container.Resolve(serviceType);
}
catch
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return _container.ResolveAll(serviceType);
}
catch
{
return new List<object>();
}
}
}
}
Open the Global.asax and register types and set DependencyResolver in Application_Start:
Hide Copy Code
protected void Application_Start() {
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
var container = new UnityContainer();
container.RegisterType<ICatalogService, CatalogService>
(new PerThreadLifetimeManager())
.RegisterType<IDALContext, DALContext>();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}

That's all, enjoy!
EF UoC的更多相关文章
- %E3%80%90%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E3%80%91
"%3Cdiv%20class%3D%22htmledit_views%22%20id%3D%22content_views%22%3E%0A%20%20%20%20%20%20%20%20 ...
- 你必须知道的EF知识和经验
注意:以下内容如果没有特别申明,默认使用的EF6.0版本,code first模式. 推荐MiniProfiler插件 工欲善其事,必先利其器. 我们使用EF和在很大程度提高了开发速度,不过随之带来的 ...
- 采用MiniProfiler监控EF与.NET MVC项目(Entity Framework 延伸系列1)
前言 Entity Framework 延伸系列目录 今天来说说EF与MVC项目的性能检测和监控 首先,先介绍一下今天我们使用的工具吧. MiniProfiler~ 这个东西的介绍如下: MVC Mi ...
- 采用EntityFramework.Extended 对EF进行扩展(Entity Framework 延伸系列2)
前言 Entity Framework 延伸系列目录 今天我们来讲讲EntityFramework.Extended 首先科普一下这个EntityFramework.Extended是什么,如下: 这 ...
- EntityFramework之DetectChanges's Secrets(三)(我为EF正名)
前言 对于应用程序开发者来说,通常不需要考虑太多对于Entity Framework中的变更追踪(change tracking),但是变更追踪和DetectChanges方法是栈的一部分,在这其中, ...
- ASP.NET从零开始学习EF的增删改查
ASP.NET从零开始学习EF的增删改查 最近辞职了,但是离真正的离职还有一段时间,趁着这段空档期,总想着写些东西,想来想去,也不是很明确到底想写个啥,但是闲着也是够 ...
- 使用EF CodeFirst 创建数据库
EntityFramework 在VS2015添加新建项时,选择数据->ADO.NET 实体数据模型,有一下选项 来自数据库的EF设计器,这个就是我们最常用的EntityFramework设计模 ...
- EF上下文对象线程内唯一性与优化
在一次请求中,即一个线程内,若是用到EF数据上下文对象,就创建一个,这也加是很多人的代码中习惯在使用上下文对象时,习惯将对象建立在using中,也是为了尽早释放上下文对象, 但是如果有一个业务逻辑调用 ...
- EF里Guid类型数据的自增长、时间戳和复杂类型的用法
通过前两章Lodging和Destination类的演示,大家肯定基本了解Code First是怎么玩的了,本章继续演示一些很实用的东西.文章的开头提示下:提供的demo为了后面演示效果,前面代码有些 ...
随机推荐
- Unity3D研究院之Prefab里面的Prefab关联问题
最近在做UI部分中遇到了这样的问题,就是Prefab里面预制了Prefab.可是在Unity里面一旦Prefab预制了Prefab那么内部的Prefab就失去关联.导致与如果要改内部的Prefab需要 ...
- 使用HTML5里的classList操作CSS类
在HTML5 API里,页面DOM里的每个节点上都有一个classList对象,程序员可以使用里面的方法新增.删除.修改节点上的CSS类.使用classList,程序员还可以用它来判断某个节点是否被赋 ...
- ASP.NET MVC5 网站开发实践(二) Member区域 - 咨询管理的架构
咨询.留言.投诉等功能是网站应具备的基本功能,可以加强管理员与用户的交流,在上次完成文章部分后,这次开始做Member区域的咨询功能(留言.投诉都是咨询).咨询跟文章非常相似,而且内容更少.更简单. ...
- Android 设置对话框全屏
1.在styles.xml中添加一个style: <style name="Dialog_Fullscreen"> <item name="androi ...
- scikit-learn 逻辑回归类库使用小结
之前在逻辑回归原理小结这篇文章中,对逻辑回归的原理做了小结.这里接着对scikit-learn中逻辑回归类库的我的使用经验做一个总结.重点讲述调参中要注意的事项. 1. 概述 在scikit-lear ...
- winform中textbox属性Multiline=true时全选
1.文本框右键属性 => 添加KeyDown事件. 2.添加如下代码: private void txt_result_KeyDown(object sender, KeyEventArgs e ...
- 【集合框架】JDK1.8源码分析之Comparable && Comparator(九)
一.前言 在Java集合框架里面,各种集合的操作很大程度上都离不开Comparable和Comparator,虽然它们与集合没有显示的关系,但是它们只有在集合里面的时候才能发挥最大的威力.下面是开始我 ...
- Android之实现ViewPagerIndicator
PS:最近一直忙于学习任务,一直没有时间去写博客.今天周六,终于有时间了. 学习任务: 1.打造一个自己的ViewPagerIndicator 最近被安排了一大堆的学习任务,感觉老板还是很好的,让 ...
- MongoDB-基础-limit-skip-sort
MongoDB Limit() 方法 如果你需要在MongoDB中读取指定数量的数据记录,可以使用MongoDB的Limit方法,limit()方法接受一个数字参数,该参数指定从MongoDB中读取的 ...
- js赋值运算的理解
简介 js引擎由于为了效率,很多时候的非直接量赋值都不是copy一份在赋值给新的变量,而是一个引用 ps:直接量:直接值数字字符串等 为什么使用len = doms.length; 里的len效率要比 ...












