MVC中的Repository模式


http://www.cnblogs.com/zhongxinWang/archive/2012/02/22/2360283.html

1.首先创建一个空的MVC3应用程序,命名为MyRepository.Web,解决方案命名为MyRepository。

2.添加一个类库项目,命名为MyRepository.DAL,添加一个文件夹命名为Repository来存放业务逻辑。

3.继续添加一个类库项目,命名为MyRepository.Domain,添加两个文件夹Models和Infrastructure。

Models来存放实体,Infrastructure来存放几个基本的类。现在目录结构已经搭建好了。

4.用NuGet确保三个项目添加了相同版本的EF,在MyRepository.DAL中引用MyRepository.Domain,在

MyRepository.Web中引用MyRepository.Domain和MyRepository.DAL。

5.在MyRepository.Domain中添加一个类BookStoreDbContext。使用EF来对数据库进行连接。

复制代码
public class BookStoreDbContext : DbContext
    {
        //EF从配置文件中寻找name=BookStore的数据库链接。
        //如果不指定: base("BookStore"),则寻找name=BookStoreDbContext的数据库连接
        public BookStoreDbContext()
            : base("BookStore")
        {

        }
    }
复制代码

下面是配置文件:

  <connectionStrings>
    <add name="BookStore" providerName="System.Data.SqlClient" connectionString="Data Source=.\sqlexpress;Initial Catalog=BookStore;User ID=Wangzx;Password=Wangzx01;Persist Security Info=True;"/>
  </connectionStrings>

 DbContext用来与数据库建立连接完成对数据的相关操作,如果不使用Repository模式,DbContext的实例化一般放在Controller中来使用。下面开始介绍MVC3中使用Repository模式。

先把Repository模式的类图贴出来:

6.先介绍最主要的接口IRepository,该接口定义了最通用的业务逻辑操作:增、删、该。这些操作对任何一个实体的操作都是一样的。该类添加在MyRepository.Domain项目的Infrastructure文件夹中。

下面是代码:

复制代码
namespace MyRepository.Domain.Infrastructure
{
    public interface IRepository<TEntity> where TEntity : class
    {
        void Insert(TEntity entity);
        void Update(TEntity entity);
        void Delete(TEntity entity);
    }
}
复制代码

这里使用泛型接口,可以用于Book,Author等不同实体的操作,只要把站位符替换掉即可。

7.下面是Repository泛型基类,它实现了IRepository接口,并使用的是泛型实现,用于对多个不同实体的操作。

具体的操作是通过DbContext来实现的,所以构造函数中要提供一个DbContext参数。该类与IRepository位于相同目录下面。

代码:

复制代码
namespace MyRepository.Domain.Infrastructure
{
    public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        protected BookStoreDbContext dbContext;
        protected DbSet<TEntity> dbSet;

        public Repository(BookStoreDbContext dbContext)
        {
            this.dbContext = dbContext;
            this.dbSet = dbContext.Set<TEntity>();
        }
        public void Insert(TEntity entity)
        {
            dbSet.Add(entity);
        }
        public void Update(TEntity entity)
        {
            dbSet.Attach(entity);
            dbContext.Entry(entity).State = EntityState.Modified;
        }
        public void Delete(TEntity entity)
        {
            if (dbContext.Entry(entity).State == EntityState.Detached)
            {
                dbSet.Attach(entity);
            }
            dbSet.Remove(entity);
        }
    }
}
复制代码

Repository类是对普遍业务操作泛型实现的地方,主要是对数据库的修改查询操作。下面的UnitOfWork 和IUnitOfWork也属于Infrastructure,这两个是用于对数据的保存。Repository和UnitOfWork都使用DbContext来对数据库进行操作,所以都有一个DbContext的字段。

public interface IUnitOfWork : IDisposable
    {
        DbContext Context { get; }
        void Save();
        bool IsDisposed { get; }
    }
复制代码
 /// <summary>
    /// 用于对数据的保存操作
    /// </summary>
    public class UnitOfWork : IUnitOfWork
    {
        private  readonly BookStoreDbContext _context;
        public DbContext Context
        {
            get { return _context; }
        }

        public event EventHandler Disposed;

        public bool IsDisposed { get; private set; }
        public void Dispose()
        {
            Dispose(true);
        }
        public virtual void Dispose(bool disposing)
        {
            lock (this)
            {
                if (disposing && !IsDisposed)
                {
                    _context.Dispose();
                    var evt = Disposed;
                    if (evt != null) evt(this, EventArgs.Empty);
                    Disposed = null;
                    IsDisposed = true;
                    GC.SuppressFinalize(this);
                }
            }
        }

        public UnitOfWork(BookStoreDbContext context)
        {
            _context = context;
        }

        public void Save()
        {
            _context.SaveChanges();
        }

        ~UnitOfWork()
        {
            Dispose(false);
        }
    }
复制代码

到现在Repository模式的框架已经搭建好了,下面使用Book实体来完成一个具体的业务操作,对其他实体的操作都是下面一样的步骤。

8.1:添加实体

    在MyRepository.Domain.Models文件夹下面添加一个实体类Book。

复制代码
[Table("Book")]
    public class Book
    {
        public int Id { get; set; }

        public string ISBN { get; set; }

        public string Title { get; set; }

        public string Type { get; set; }
    }
复制代码

8.2:修改DbContext

然后修改我们的DbContext类中添加一个DbSet属性,这样EF会在数据库中添加Book表。

复制代码
 public class BookStoreDbContext : DbContext
    {
        //EF从配置文件中寻找name=BookStore的数据库链接。
        //如果不指定: base("BookStore"),则寻找name=BookStoreDbContext的数据库连接
        public BookStoreDbContext()
            : base("BookStore")
        {

        }

        public DbSet<Book> BookCollection { get; set; }
    }
复制代码

8.3:添加IXXXRepository接口

在Repository类图中,只介绍了IRepoitory和Repository两个公共的类,而IXXXRepository和XXXRepository是具体使用时添加的类。下面在MyRepository.Domain文件夹下面添加一个IBookRepository,这个接口是对现有Book实体业务的扩展。可以看出该接口包含的操作种类多于IRepository接口。

    public interface IBookRepository : IRepository<Book>
    {
        //其他业务操作,在控制器中一般使用的是该接口
        IList<Book> GetAllBooks();
    }

 8.4:实现BookRepository

在MyRepository.DAL.Repository目录下面添加一个BookRepository类。

复制代码
 public class BookRepository : Repository<Book>, IBookRepository
    {
        //在执行子类构造函数之前,先执行基类Repository<Book>的构造函数
        public BookRepository(BookStoreDbContext dbcontext)
            : base(dbcontext)
        {
        }

        public IList<Book> GetAllBooks()
        {
            var list = dbContext.BookCollection;
            return list.OrderBy(x => x.ISBN).ToList();
        }
    }
复制代码

     BookRepository类继承了对Book实体的所有业务操作,公共的操作在Repository<Book>中。因为BookRepository继承自Repository<Book>,而Repository<TEntity>继承并实现了IRepository<TEntity>,所以BookRepository不需要再次实现IRepository<TEntity>接口定义的方法,如果需要可以覆盖Repository<Book>的公共操作。

     IBookRepository中定义了BookRepository的特有业务操作,在BookRepository必须给予实现。IBookRepository必须继承自IRepository,这样在控制器中使用IBookRepository能够包含BookRepository的所有操作。在控制器结合IOC时IBookRepository能够很好的引用BookRepository对象。

   其实在企业项目中,BookRepository与MyRepository.Web中的C与V操作是不同步的。就是说不是在BookRepository完成后就立刻去写BookController,在一个控制器中可能会包含多个IXXXRepository接口类型的属性,在构造时接收XXXRepository对象。但是在这里我直接写一个简单的BookController并且不使用IOC,来简单介绍Repository模式。

9

在MyRepository.Web.Controllers中添加一个控制器MyRepository.Web.BookController

复制代码
public class BookController : Controller
    {
        private IBookRepository bookRepository;
        private IUnitOfWork unitOfWork;

        public BookController()
        {
            BookStoreDbContext bookStoreDbContext = new BookStoreDbContext(); 
            bookRepository = new BookRepository(bookStoreDbContext);
            unitOfWork = new UnitOfWork(bookStoreDbContext);
        }

        public ViewResult List()
        {
            IList<Book> listBook = bookRepository.GetAllBooks();
            return View(listBook);
        }

        [HttpGet]
        public ViewResult Create()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Create(Book book)
        {
            bookRepository.Insert(book);
            unitOfWork.Save();
            return RedirectToAction("List");
        }
    }
复制代码

对于View的添加,路由的设置属于MVC3的内容:http://www.bbsmvc.com/mvclearn/thread-173-1-1.html。在MVC3这本书中还提到IOC也可以结合该列子。下面是数据库和运行效果。

 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值