前面已经介绍了数据持久化部分的数据模型设计,现在我们来介绍数据操作部分的设计,也就是数据的增、删、改、查等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.   提升业务需求灵活性;

  四、         面向对象编程中,继承、重写等基本操作是需要考虑的,而且上面也提到,数据操作基本是通过DbContext、DbSet类实现,这些数据表操作肯定可以、也有必要抽象出操作父类(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 );}elselist = 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. 数据仓储设计的基本概念

    一.维度建模基本概念 维度建模(dimensional modeling)是专门用于分析型数据库.数据仓库.数 据集市建模的方法.数据集市可以理解为是一种"小型数据仓库". 维度表 ...

  2. 后台产品的数据可视化图表产品设计

    前些天,做后台的数据子系统的时候,需要用到一些可视化的数据图表,我用到了一个自认为效果比较好,而且比较方便的方式来实现. 在网上巴拉巴拉地找了一番,目前用到这种方法来做数据图表的人并不多,我给身边的朋 ...

  3. 仿wordpress管理后台设计的后台管理框架

    仿wordpress管理后台设计的后台管理框架 本Markdown编辑器使用[StackEdit][6]修改而来,用它写博客,将会带来全新的体验哦: html的padding-top来实现整体下移,然 ...

  4. 分享6个国内优秀Java后台管理框架的开源项目

    分享6个国内优秀Java后台管理框架的开源项目,建议收藏! Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言.Java 技术具有卓越的通用性.高效性.平台移植性和安全性,广泛应用于PC.数 ...

  5. 一个页面区分管理者和普通用户如何设计_产品经理要做的操作权限/数据权限设计...

    产品经理在工作中还需要知道一个:用户权限设计能力.权限设计理念贯穿于后台产品.以及用户前端产品. 权限能力包括两类:数据权限.系统操作权限 有的人会好奇,为什么前端产品会有有权限管理的要求?接下来我将 ...

  6. 一步步带你做vue后台管理框架(三)——登录功能

    系列教程<一步步带你做vue后台管理框架>第三课 github地址:vue-framework-wz 线上体验地址:立即体验 <一步步带你做vue后台管理框架>第一课:介绍框架 ...

  7. (转)超全面设计指南:如何做大屏数据可视化设计?

    数据可视化是一门庞大系统的科学,本文所有讨论仅针对大屏数据可视化这一特定领域.管中窥豹,如有遗漏或不足之处欢迎大家讨论交流. 文章结构及思维导图: 一.基础概念 1. 什么是数据可视化 把相对复杂.抽 ...

  8. 数据可视化设计的UI实用模板素材

    后台界面的设计需求很常见.商业活动中,人们希望通过一个数据可视化界面来展示所有的信息.趋势和风险,并实时更新,助力于财务分析预测. 后台界面应该是一种引人注目.简单直接的导航方式. (后台界面)Das ...

  9. 丽水数据可视化设计价格_B端产品设计数据可视化图表选择篇

    本文一共6040文字,阅读大概需要15分钟 近期在做直播后台内容数字化渠道升级 ,其中有个工作是需要把大量的数据表格转换成为可视化图表,接到需求一脸懵的我,冒出几个问题 1.什么是数据可视化? 2.数 ...

最新文章

  1. LeetCode 445. Add Two Numbers II--面试算法题--C++,Python解法
  2. sfdisk命令的使用技巧
  3. android 服务的应用,在Activity中实现背景音乐播放
  4. 2016年第七届蓝桥杯 - 省赛 - C/C++大学A组 - I. 密码脱落
  5. ajax 数据 有序号,在ajax中添加序列号
  6. 花书+吴恩达深度学习(二三)结构化概率模型(贝叶斯网络、马尔可夫随机场)
  7. linux服务端口加密,linux – 如何通过单个端口处理加密和未加密的http连接
  8. 朱光潜:要有悲剧,才能算人生
  9. 4k hidpi 黑苹果_黑苹果如何通过开启HIDPI来增强显示效果?
  10. 央行上海总部推出企业信用报告网银查询渠道
  11. windows粘贴不了
  12. mysql5.7.19winx64安装_mysql5.7.19winx64安装配置方法图文教程(win10)
  13. mongo-go-driver 踩坑心得 server selection error
  14. 什么是B/S开发技术?
  15. 计算机应用基础考查方案,《计算机应用基础》考查方案
  16. 对error C2079: 'stu' uses undefined struct 'Students'的解释
  17. unity实现神笔马良效果
  18. jvm mat分析dump文件
  19. 练手小项目,爬取3DM图片
  20. 阿里内部总结的微服务笔记,从入门到精通,初学者也能学的会

热门文章

  1. 汤姆猫炫跑鸿蒙,汤姆猫炫跑3游戏预约-汤姆猫炫跑3游戏最新版v1.2.1.117 - 趣趣手游网...
  2. 扫地机器人湿地_扫地机器人的制作方法
  3. HTML5完成的12306页面的制作
  4. SUN公司JavaMail发送邮件
  5. P2020_RDB开发板用codeWarrior TAP下载bootrom.bin
  6. 像星空一样汇聚然后爆炸开来的AE粒子模板
  7. 计算机屏幕变红色,Windows10系统电脑屏幕变成红色如何解决
  8. 对linux中级用户有用的20个命令
  9. CentOS8 查看系统版本
  10. Cesium学习笔记(十):粒子系统(Particle System)