轻量级ORM框架QX_Frame.Bantina系列讲解(开源)
一、框架简介 http://www.cnblogs.com/qixiaoyizhan/p/7417467.html
二、框架使用方式介绍 http://www.cnblogs.com/qixiaoyizhan/p/7418058.html
三、框架性能对比 近期补充
【前言】
ORM(Object Relational Mapping)框架采用元数据来描述对象一关系映射细节,框架根据对象之间的关系以及对象自身的属性可以框架内部自动生成sql语句,简化了程序员的sql开发,极大地提升了编码效率,同时也使得程序错误代码的发生率降低,提高程序的可读性,在使用上相较传统的DAO Sql语句的写法有极大的优势。
任何优秀的新事物都是一把双刃剑,有利就有弊,关键看使用这把剑的人如何去操作。不尽其然,ORM框架也是有碧如执行比较慢缺点,但是舍弃性能的同时提升开发效率,某些程度上也是可以广为接受的,因此,ORM开发的重点又突出在了易使用和高性能两个方面。
今天,我这里推出一款本人花费一周时间独立开发的ORM框架:Bantina 第一版
该框架采用特性的方式做数据表关系映射,吸纳了Microsoft的EntityFramework的一些思想,并且简化了EntityFramework的功能,同时极力向原生的sql语句靠拢,以提高程序执行效率。自带缓存的支持提升查询效率,作为Bantina第一版,我们先暂时支持SqlServer数据库的操作,在后续的版本升级中,逐步开放对Mysql、Oracle甚至是NoSql的支持。
下面我们对Bantina 1.0 做详细介绍。
介绍之前,我们先在本地创建一个数据库,作为演示使用实例以及数据库查询对比的操作对象,该数据库结构如下图所示:
数据库名:DB_QX_Frame_Test
其中包含三张表:TB_ClassName (班级名称)
TB_People (人员表)
TB_Score (分数表)
表之间的关系是TB_People中有TB_ClassName的外键
【框架功能特性】
我们先对Bantina1.0 ORM框架支持的功能做列表介绍,突出框架封装的简单操作方法以及框架支持的简介操作的特性。
1、框架采用继承使用的方式,沿袭了EntityFramework的初始化方法
数据库实体类继承自框架Bantina,然后在构造方法里面提供数据库连接字符串,有多种参数可供选择。
public class DB_QX_Frame_Test : Bantina { public DB_QX_Frame_Test() : base("data source=.;initial catalog=DB_QX_Frame_Test;persist security info=True;user id=Sa;password=Sa123456;MultipleActiveResultSets=True;App=EntityFramework") { } }
2、数据库读写分离的支持
在数据库初始化的同时,传入的数据库连接字符串可以进行读写库的分离设置,极大方便了数据库读写分离的操作(框架原生支持读写分离)。
如果传递单条连接字符串,那么读写库使用一个,相当于关闭读写分离。
3、特性标签的方式标记实体类
该特性沿袭了EntityFramework的特点,但是并不一定追求实体类一定要和数据库结构完全一致,不存在匹配一致性检测,所有的数据库表字段使用特性标签的方式标记识别。
在主外键上,直接将外键表的属性添加进主表即可,并添加标签[ForeignTable]声明外键表即可。
[Table(TableName = "TB_People")] public class TB_People { [Key] public Guid Uid { get; set; } [Column] public string Name { get; set; } [Column] public int Age { get; set; } [Column] [ForeignKey] public int ClassId { get; set; } [ForeignTable] public TB_ClassName TB_ClassName { get; set; } } [Table(TableName = "TB_ClassName")] public class TB_ClassName { // PK(identity) [Key] public Int32 ClassId { get; set; } // [Column] public String ClassName { get; set; } }
这里标签Table可以支持数据库的表名和实体类的表名不一致,在参数TableName声明数据库真实的表名即可。
在alpha版本里,字段也是支持修改并配置的,但是为了支持后续的特性Lambda表达式参数,将此功能去掉,以便简化框架代码,因此,字段名称是需要类属性和表的字段完全一致的情况下进行操作的。
这里字段的标签Key以及Column也是有必要的,在后续的使用中会进行逐步讲解。这里大家可能会有疑问,每个属性手动写标签会比较多,比较麻烦,这里有专门匹配的代码生成器进行生成,避免了手动添加的繁琐。
4、框架自带智能缓存特性
Sql查询的耗时主要出现在大量数据的查询上,一套系统如果没有良好的设计,每次获取数据都要进行大量耗时查询操作,那么系统的用户体验感将会降到极低,直接影响到了用户的使用心情。
Bantina框架原生自带了缓存特性,在对数据库的查询操作时,并不会直接对所有数据进行缓存,只会对当前的查询操作执行的结果进行缓存,当对操作的表进行增删改操作时,又会智能识别下次重新获取数据并覆盖缓存。这样避免了全表数据缓存查询的耗时时间,又能在数据查询的缓存支持上得到很好的效率。
缓存的智能消除,极力维护了系统数据一致性,避免了等待缓存过期造成的数据尴尬问题。
这里查询同一组集合数据的三段同样的代码耗时展示(单位:毫秒):
可以看出,第一次是从数据库进行获取数据,并添加到缓存,第二次和第三次是从缓存中获取的数据,速度非常快;
5、提供多种常用执行方法,无需后续数据格式转化以及遍历操作
原生支持各种常用查询结果,不需要后续进行遍历等格式转化操作,一切以对象及集合说话,完全符合面向对象行为方式。
这里的Query查询方法包含了Entity<T>单个实体对象的查询以及Entities<T>多个实体对象List列表的查询。
TEntity QueryEntity<TEntity>(Expression<Func<TEntity, bool>> where) where TEntity : class; List<TEntity> QueryEntities<TEntity>() where TEntity : class; List<TEntity> QueryEntities<TEntity>(Expression<Func<TEntity, bool>> where) where TEntity : class;
这里我展示Bantina常用的方法接口:
public interface IBantina { Task<bool> Add<TEntity>(TEntity entity) where TEntity : class; Task<bool> Update<TEntity>(TEntity entity) where TEntity : class; Task<bool> Update<TEntity>(TEntity entity, Expression<Func<TEntity, bool>> where) where TEntity : class; Task<bool> Delete<TEntity>(TEntity entity) where TEntity : class; Task<bool> Delete<TEntity>(Expression<Func<TEntity, bool>> where) where TEntity : class; bool QueryExist<TEntity>(Expression<Func<TEntity, bool>> where) where TEntity : class; int QueryCount<TEntity>() where TEntity : class; int QueryCount<TEntity>(Expression<Func<TEntity, bool>> where) where TEntity : class; TEntity QueryEntity<TEntity>(Expression<Func<TEntity, bool>> where) where TEntity : class; List<TEntity> QueryEntities<TEntity>() where TEntity : class; List<TEntity> QueryEntities<TEntity>(Expression<Func<TEntity, bool>> where) where TEntity : class; List<TEntity> QueryEntitiesPaging<TEntity, TKey>(int pageIndex, int pageSize, Expression<Func<TEntity, TKey>> orderBy, bool isDESC = false) where TEntity : class; List<TEntity> QueryEntitiesPaging<TEntity, TKey>(int pageIndex, int pageSize, Expression<Func<TEntity, TKey>> orderBy, Expression<Func<TEntity, bool>> where, bool isDESC = false) where TEntity : class; List<TEntity> QueryEntitiesPaging<TEntity, TKey>(int pageIndex, int pageSize, Expression<Func<TEntity, TKey>> orderBy, out int count, bool isDESC = false) where TEntity : class; List<TEntity> QueryEntitiesPaging<TEntity, TKey>(int pageIndex, int pageSize, Expression<Func<TEntity, TKey>> orderBy, Expression<Func<TEntity, bool>> where, out int count, bool isDESC = false) where TEntity : class; DataTable QueryDataTable<TEntity>(string sql, params SqlParameter[] parms) where TEntity : class; DataSet QueryDataDataSet<TEntity>(string sql, params SqlParameter[] parms) where TEntity : class; int ExecuteSql<TEntity>(string sql, params SqlParameter[] parms) where TEntity : class; List<TEntity> ExecuteSqlToList<TEntity>(string sql, params SqlParameter[] parms) where TEntity : class; int ExecuteStoredProcedure<TEntity>(string storedProcedureName, params object[] parms) where TEntity : class; List<TEntity> ExecuteStoredProcedureToList<TEntity>(string storedProcedureName, params object[] parms) where TEntity : class; }
Bantina Method Interface
6、原生自带分页查询
数据库的查询自带分页查询方法,不需要我们后续进行查全部集合后的分页操作,极大地提升了开发的效率。
分页的条件完整全面且易于传递及操作,对程序员的开发有较大的帮助。
List<TEntity> QueryEntitiesPaging<TEntity, TKey>(int pageIndex, int pageSize, Expression<Func<TEntity, TKey>> orderBy, bool isDESC = false) where TEntity : class; List<TEntity> QueryEntitiesPaging<TEntity, TKey>(int pageIndex, int pageSize, Expression<Func<TEntity, TKey>> orderBy, Expression<Func<TEntity, bool>> where, bool isDESC = false) where TEntity : class; List<TEntity> QueryEntitiesPaging<TEntity, TKey>(int pageIndex, int pageSize, Expression<Func<TEntity, TKey>> orderBy, out int count, bool isDESC = false) where TEntity : class; List<TEntity> QueryEntitiesPaging<TEntity, TKey>(int pageIndex, int pageSize, Expression<Func<TEntity, TKey>> orderBy, Expression<Func<TEntity, bool>> where, out int count, bool isDESC = false) where TEntity : class;
7、Lambda表达式的支持
对数据集合的查询条件全部统一使用Lambda表达式,便于操作的同时,极大降低了手动拼写错误的风险。
这里的Lambda表达式完全使用标准的Linq风格,在Lambda的支持条件下,查询条件对String类型的字段默认支持一下几种筛选条件:
t.Equals(""); //完全匹配
t.Contains(""); //模糊查询
t.StartWith(""); //模糊查询起始字符固定
t.EndsWith(""); //模糊查询结束字符固定
...
例如我们需要查询People表Name字段包含2的所有数据的数目,操作方法如下图所示:
8、原生SQL语句方式和存储过程的支持
Bantina在提倡框架风格使用的基础上,也提供了对原生SQL语句和存储过程执行的支持,便于适应多变的生产环境。
9、增删改使用Task异步执行的方式
Bantina的增删改操作全部采用异步Task线程执行的方式,提高了程序的执行效率。
在多行数据的批量添加修改删除循环调用的时候,会提升插入操作执行的效率。
默认对异步的支持,也可以使得web服务的响应得到提升,间接提高了用户体验感。
Task<bool> Add<TEntity>(TEntity entity) where TEntity : class; Task<bool> Update<TEntity>(TEntity entity) where TEntity : class; Task<bool> Update<TEntity>(TEntity entity, Expression<Func<TEntity, bool>> where) where TEntity : class; Task<bool> Delete<TEntity>(TEntity entity) where TEntity : class; Task<bool> Delete<TEntity>(Expression<Func<TEntity, bool>> where) where TEntity : class;
10、对事务操作的支持
Bantina框架封装了对事务的支持,而且调用非常简洁。
只需要数据库上下文对象调用事务方法,然后传递一个委托给方法作为参数执行委托事件即可。
下面我使用了匿名委托的方式进行调用事务执行操作,在委托方法里面分别执行了几组需要支持事务操作的数据库操作,然后方法自动提交事务,如果有事务失败的操作,那么方法会自动回滚操作。
代码展示如下图所示:
11、支持主外键多表关联查询操作
Bantina可以通过配置主外键关系,通过特定的特性标签来标识主外键关系,然后达到主外键关联查询的目的。
配置代码见该介绍第三条 3、特性标签的方式标记实体类
例如我们要支持关联外键表TB_ClassName的查询,并将班级的名称显示,通过配置后,我们可以进行如下查询操作:
查询结果如下图所示:
Bantina实现了如上的关联查询操作方式。
介绍完我们的Bantina框架后,我们将在下一章对Bantina的使用方法进行介绍:
二、框架使用方式介绍 http://www.cnblogs.com/qixiaoyizhan/p/7418058.html
【获取方式】
1、Nuget获取:Nuget搜索 QX_Frame.Helper_DG
2、GitHub查看源代码:https://github.com/dong666/QX_Frame.Helper_DG
3、联系本人获取,联系方式在下方博客签名中,qq、email均可。