泛型Repository的使用

以前一直用业务模型跟Repository一对一的形式,但是看到很多开源项目中都是使用泛型的Repository,觉得会简便一些,但是也存在一些问题。

比如member表是不应该有删除接口的, 如果使用泛型的repository的话,delete方法会入侵member类。不过不管怎么说,使用泛型的仓储会减少很多代码量和重复工作。

1、建立实体类(这是一个任务计划的类,下一篇还要讲怎么在mvc中写计划任务,比如要过24小时自动清理一下缓存,比如跟国际金融相关的,要24小时获取一次汇率等等):

public class ScheduleTask {

        /// <summary>
        /// 主键ID
        /// </summary>
        public int ID { get; set; }
        
        /// <summary>
        /// 任务名字
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 运行周期(秒)
        /// </summary>
        public int Seconds { get; set; }

        /// <summary>
        /// 相应的ITask类的类型
        /// </summary>
        public string Type { get; set; }

        /// <summary>
        /// 任务是否启用
        /// </summary>
        public bool Enabled { get; set; }

        /// <summary>
        /// 遇到错误是否停止
        /// </summary>
        public bool StopOnError { get; set; }

        /// <summary>
        /// 最后开始时间
        /// </summary>
        public DateTime? LastStartDate { get; set; }

        /// <summary>
        /// 最后结束时间
        /// </summary>
        public DateTime? LastEndDate { get; set; }

        /// <summary>
        /// 最后执行成功时间
        /// </summary>
        public DateTime? LastSuccessDate { get; set; }
    }

 2、创建DbContext:

public class HelperDbContext : DbContext {
        public HelperDbContext()
            : base("TbsContext") {

        }

        public DbSet<ScheduleTask> ScheduleTasks { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder) {
            modelBuilder.Configurations.Add(new ScheduleTaskMap());
            base.OnModelCreating(modelBuilder);
        }
    }

 解释一下,base("TbsContext") 是读取webconfig里面名为TbsContext的数据库链接字符串,如果不写,应该是默认读取HelperDbContext

 

3、重点来了:IRepository接口

public partial interface IRepository<T> where T : class
    {
        T GetById(object id);

        void SaveChanges();

        void Insert(T entity);

        void Update(T entity);

        void Delete(T entity);

        IQueryable<T> Table { get; }

        IQueryable<T> TableNoTracking { get; }
    }

 4、实现:

public partial class EFRepository<T> : IRepository<T> where T : class {
        private HelperDbContext _context = new HelperDbContext();

        private IDbSet<T> _entities;

        /// <summary>
        /// Entities
        /// </summary>
        protected virtual IDbSet<T> Entities {
            get {
                if (_entities == null)
                    _entities = _context.Set<T>();
                return _entities;
            }
        }

        public T GetById(object id) {
            return this.Entities.Find(id);
        }

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

        public void Insert(T entity) {
            try {
                if (entity == null)
                    throw new ArgumentNullException("entity");

                this.Entities.Add(entity);

                this._context.SaveChanges();
            }
            catch (DbEntityValidationException dbEx) {
                var msg = string.Empty;

                foreach (var validationErrors in dbEx.EntityValidationErrors)
                    foreach (var validationError in validationErrors.ValidationErrors)
                        msg += string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage) + Environment.NewLine;

                var fail = new Exception(msg, dbEx);
                //Debug.WriteLine(fail.Message, fail);
                throw fail;
            }
        }

        public void Update(T entity) {
            try {
                if (entity == null)
                    throw new ArgumentNullException("entity");

                this._context.SaveChanges();
            }
            catch (DbEntityValidationException dbEx) {
                var msg = string.Empty;

                foreach (var validationErrors in dbEx.EntityValidationErrors)
                    foreach (var validationError in validationErrors.ValidationErrors)
                        msg += Environment.NewLine + string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);

                var fail = new Exception(msg, dbEx);
                //Debug.WriteLine(fail.Message, fail);
                throw fail;
            }
        }

        public void Delete(T entity) {
            try {
                if (entity == null)
                    throw new ArgumentNullException("entity");

                this.Entities.Remove(entity);

                this._context.SaveChanges();
            }
            catch (DbEntityValidationException dbEx) {
                var msg = string.Empty;

                foreach (var validationErrors in dbEx.EntityValidationErrors)
                    foreach (var validationError in validationErrors.ValidationErrors)
                        msg += Environment.NewLine + string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);

                var fail = new Exception(msg, dbEx);
                //Debug.WriteLine(fail.Message, fail);
                throw fail;
            }
        }

        public IQueryable<T> Table {
            get {
                return this.Entities;
            }
        }

        public IQueryable<T> TableNoTracking {
            get {
                return this.Entities.AsNoTracking();
            }
        }
    }

 5、在IOC中注册一下,不注册的话就用常规的接口实现的写法就可以了,栗子中是ninject

ninjectKernel.Bind(typeof(IRepository<>)).To(typeof(EFRepository<>)); 

 6、使用案例:

private readonly IRepository<ScheduleTask> _repo;
        public HomeController(IRepository<ScheduleTask> repo) {
            this._repo = repo;
        }
             
        public ActionResult Index() {

            var aa = _repo.Table.SingleOrDefault();

            return Content(aa.Name);

        }

* 说明一下,最好不要在controller中直接调用数据访问层,应该建一个service层,然后service暴露操作crud

posted @ 2015-07-04 15:03  Charisma.  阅读(763)  评论(0)    收藏  举报