后台管理框架之五 :数据仓储设计

  前面已经介绍了数据持久化部分的数据模型设计,现在我们来介绍数据操作部分的设计,也就是数据的增、删、改、查等CRUDQ操作的仓储设计。仓储设计主要依照以下几个思路:

  一、         本项目数据操作依拖于EF框架,EF框架的数据操作主要按以下步骤进行:

  1.   定义一个继承自System.Data.Entity.Infrastructure.DbContext类的子类;

  2.   子类中增加System.Data.Entity.DbSet<TEntity>数据集对象;

  3.   操作DbSet数据集,针对性地进行增、删、改、查操作;

  4.   调用System.Data.Entity.Infrastructure.DbContext.SaveChanges(),将变动的实体数据写入数据库,实现数据持久化。

  按照以上思路,将要针对每个实体数据表定义DbContext类,如果数据表较多,重复代码就会有很多,这不是我们所需要的,而泛型DbContext< TEntity>是非常好的解决办法。

  EF6.1框架中,DbContext类已经包含一个DbSet类的对象:Set,完全可以使用Set进行数据操作,而不需要再单独定义一个DbSet类对象。其它的EF版本我没有使用过,如果没有这个Set对象,可以在DbContext< TEntity>类中定义一个Set< TEntity >进行数据操作。

  二、         为了方便、规范对DbContext< TEntity>类对象的创建,项目可通过“简单工厂”定义如何获取一个DbContext< TEntity>,当然这个简单工作也应该是泛型的。同时也应该定义DbContext< TEntity>对象资源的释放接口。

  三、         数据表的操作基本就是CRUDQ操作,所以接口(IRepository)应该是不可缺少的。使用接口主要原因:

  1.   对数据表的操作进行基本的限定(约束、规范);

  2.   方便IOC框架依赖注入;

  3.   提升业务需求灵活性;

  四、         面向对象编程中,继承、重写等基本操作是需要考虑的,而且上面也提到,数据操作基本是通过DbContextDbSet类实现,这些数据表操作肯定可以、也有必要抽象出操作父类(RepositoryBase)的,当然这些操作都可以定义成“virtual”,让各个实现类重写即可。

按照以上的思路,项目的数据仓库操作会按以下结构进行设计:

  项目的数据仓库操作按照以上模型进行设计,对于基本的数据表操作,各实际操作子类基本无需编写实现代码,仅仅需要的是定义一个ICRUDRepository<TEntity >的继承接口(如IUserRepository)和一个RepositoryBase< TEntity >的继承类(如UserRepository),然后将此定义的类实现定义的接口即可,如:

  public class UserRepository: IUserRepository {}

  当然,如果目前定义的超类无法完全满足实际需要,具体子类完全可以通过Query方法(包括Where条件表达式、Ordert条件表达、分页等)进行查询;或者仍然不能满足,完全可以利用父类的Context对象的Database属性对象,直接使用SQL语句进行各类数据操作,应该是可以完全满足要求。

  有个问题我考虑了很久,具体实体数据操作的接口基本就是空定义,是否必须得定义?经过实际验证,我最后选择了定义这些接口,主要原因是:一来为了方便使用Autofac进行注入;二来在业务定义中可直接引用接口,在此接口中更可以进行扩展,业务定义中不直接面向ICRUDRepository<TEntity >,既做到了分离、又提供了灵活性,所需做的仅仅就是复制一个接口定义而己。

  还有一个问题是在代码调试的时候碰到的,是关于DbConext<TEntity>的泛型定义的:当使用泛型DbConext<TEntity>同时使用其内置属性Set< TEntity >进行数据操作时会报错(具体错误我没有记下来,大意就是“不能识别数据实体模型”),网上没有搜到相关的解决办法,经过多方研究,最后自己摸索出方法解决了问题,就是重写DbConext  OnModelCreating方法,通过DbModelBuilder对象注册这个数据模型,具体代码如下:

protected override voidOnModelCreating(DbModelBuilder modelBuilder)

{

     base.OnModelCreating( modelBuilder );

     modelBuilder.Entity<T>();

}

  DbModelBuilder.Entity<T>()MSDN解释:将实体类型注册为模型的一部分,并返回一个可用来配置实体的对象。可对同一实体多次调用此方法以执行多行配置。

  至此,数据操作(实体模型、仓储操作)的设计已经基本完成,下一步将介绍View模型的设计。

  以下是ICRUDRepository接口的定义:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using EPF.linxy.Data.Model.Base;

namespace EPF.linxy.Data.Infrastructure
{
        public interface ICRUDRepository<T> where T : class,IEntity , new()
        {
                /// <summary>
                /// 创建实体对象并写入到缓存列表
                /// 需要调用Commit方法将修改写入到数据库
                /// </summary>
                /// <param name="entity">实体类对象</param>
                void Create(T entity);
                /// <summary>
                /// 更新缓存列表指定实体对象
                /// 需要调用Commit方法将修改写入到数据库
                /// </summary>
                /// <param name="entity">实体类对象</param>
                void Update(T entity);
                /// <summary>
                ///  设置缓存列表中指定主键Ideas的实体为删除状态
                /// 需要调用Commit方法将修改写入到数据库
                /// </summary>
                /// <param name="entity">实体类对象</param>
                void Delete(T entity);
                /// <summary>
                /// 设置缓存列表中满足指定条件的实体为删除状态
                /// 需要调用Commit方法将修改写入到数据库
                /// </summary>
                /// <param name="entity">实体类对象</param>
                void Delete(Expression<Func<T , bool>> where);

                /// <summary>
                /// 获取指定主键ID值的实体对象
                /// </summary>
                T Get(object id);
                /// <summary>
                /// 获取满足指定条件的第一条实体对象
                /// </summary>
                T Get(Expression<Func<T , bool>> where);

                /// <summary>
                /// 根据条件分页获得记录
                /// </summary>
                /// <param name="where">条件</param>
                /// <param name="orderBy">排序</param>
                /// <param name="ascending">是否升序</param>
                /// <param name="pageIndex">当前页码</param>
                /// <param name="pageSize">每页大小</param>
                /// <param name="totalRecord">总记录数</param>
                /// <returns>记录列表</returns>
                IEnumerable<T> Query(out int totalRecord , Expression<Func<T , bool>> where , string orderByKeyName="" , bool isAscending=true , int pageIndex=1 , int pageSize=20);

                /// <summary>
                /// 加载全部实体对象
                /// </summary>
                IEnumerable<T> LoadAll();
                /// <summary>
                /// 加载满足指定条件的实体对象
                /// </summary>
                IEnumerable<T> LoadAll(Expression<Func<T , bool>> where);
                /// <summary>
                /// 获取符合根据指定条件的实体对象数量
                /// </summary>
                int Count(Expression<Func<T , bool>> where);
                /// <summary>
                /// 判断符合根据指定条件的实体对象是否存在
                /// </summary>
                bool Exist(Expression<Func<T , bool>> where);

                /// <summary>
                /// 提交实体对象的变更
                /// </summary>
                /// <returns>返回影响的行数</returns>
                int Commit();
        }
}


 

  以下是RepositoryBase类的代码:

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Data.Entity;
using EPF.linxy.Data.Model.Base;
using System.Collections.Generic;

namespace EPF.linxy.Data.Infrastructure
{
	//where T : class, IEntity , new()限制当前泛型类的实参应该是一个实体数据模型,其中:
	//class : 限定T的实参必须是一个类,而不是是简单类型、接口等
	//IEntity : 限定T的实参必须是实体数据模型,IEntity是在Data.Model.Base中定义的
	//new() : 限定T的实参必须具有一个0参数的构造函数,new()必须放在最后
        public abstract class RepositoryBase<T> : ICRUDRepository<T> where T : class, IEntity , new()
        {
                private EPFDbContext<T> dataContext;
                protected readonly IDbSet<T> EntitySet;
                protected RepositoryBase(IDatabaseFactory<T> databaseFactory)
                {
                        DatabaseFactory = databaseFactory;
                        EntitySet = DataContext.Set<T>();
                }

                protected IDatabaseFactory<T> DatabaseFactory
                {
                        get;
                        private set;
                }

                public int Commit()
                {
                        return dataContext.SaveChanges();
                }

                protected EPFDbContext<T> DataContext
                {
                        get { return dataContext ?? ( dataContext = DatabaseFactory.Get() ); }
                }

                public virtual void Create(T entity)
                {
                        EntitySet.Add( entity );
                        //Commit();
                }
                public virtual void Update(T entity)
                {
                        //EntitySet.Add(entity);
                        EntitySet.Attach( entity );

                        dataContext.Entry<T>( entity ).State = EntityState.Modified;
                        //Commit();
                }
                public virtual void Delete(T entity)
                {
                        EntitySet.Remove( entity );
                        //Commit();
                }
                public virtual void Delete(Expression<Func<T , bool>> where)
                {
                        IQueryable<T> objects = EntitySet.Where<T>( where );
                        foreach ( T obj in objects )
                                EntitySet.Remove( obj );
                        //Commit();
                }

                public virtual T Get(object id)
                {
                        return EntitySet.Find( id );
                }
                public virtual T Get(Expression<Func<T , bool>> where)
                {
                        return EntitySet.Where( where ).FirstOrDefault<T>();
                }

                public virtual IEnumerable<T> LoadAll()
                {
                        return LoadAll( e => true );
                }

                public virtual IEnumerable<T> LoadAll(Expression<Func<T , bool>> where)
                {
                        return EntitySet.Where( where );
                }

                public virtual IEnumerable<T> Query(out int totalRecord , Expression<Func<T , bool>> where ,  

string orderByKeyName="" , bool isAscending=true , int pageIndex=1 , int pageSize=20)
                {
                        if ( pageIndex <= 0 ) pageIndex = 1;
                        if ( pageSize <=0 ) pageSize = int.MaxValue;

                        var list = EntitySet.Where(where.Compile()) ;
                        totalRecord = list.Count();
                        if ( totalRecord <= 0 ) return list;

                        if ( string.IsNullOrEmpty( orderByKeyName ) )
                                orderByKeyName = list.First().PrimaryKey();
                        if ( isAscending )
                        {
                                list=list.OrderBy( p => typeof( T ).GetProperty( orderByKeyName ).GetValue( p , 

null ) ).Skip( ( pageIndex-1 ) * pageSize ).Take( pageSize );
                        }
                        else
                                list = list.OrderByDescending( p => typeof( T ).GetProperty( orderByKeyName 

).GetValue(p,null) ).Skip( ( pageIndex-1 ) * pageSize ).Take( pageSize );
                  
                        return list;
                }

                public virtual int Count(Expression<Func<T , bool>> where)
                {
                        return EntitySet.Count( where.Compile() );
                }

                public virtual bool Exist(Expression<Func<T , bool>> where)
                {
                        return EntitySet.Count( where.Compile() ) > 0;
                }

        }
}


 


 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值