这款ORM框架的原版在经历过大概十几个项目的磨合,最近整理了一下,原名字为:ZhCun.Framework ,该框架辗转跟了我去过几家公司,大概从2012年出现第一个版本,当时就为简化数据库操作,从优化SQLHelper,代码生成器,一直到今天个人感觉还算好用的框架;
刚开始写完它的时候是因为当时公司的框架实在太难用(好像是实体为强类型DataTable,实体类太过笨重),但公司因为人员维护及其它的综合考虑只会让我用它做核心业务系统,有一些比较独立的小项目才会用;
这个框架我没有具体去测试过它的性能,但从技术上猜测,应该返回List 会有一定消耗,因为用到反射,但实际项目中很少有大批量的List直接返回给用户查看的;
关于ORM框架,目前有很多人开源的项目都很不错,如果非要为这套框架提出点推荐理由, 勉为其难叫:简单、轻便 吧;编译完之后大概几十K;从程序设计上不太复杂,所以在可读性对于初级程序员来说比较容易,面对核心功能的扩展可能会比较棘手,但我认为还没遇到可扩展的功能就提前做出来,代码设计出空想的东西就属于过度设计;
ORM框架名称:ZhCun.DbCore
目前NuGet 版本分两个,
1.2.0 与 2.2.0 ,其中 2.2.0 为 netstandard2.0 项目,可用于core 项目以及对应的 .Net Freamework 版本(好像是 .net 4.7 吧,具体可百度);1.2.0 在于.net 4.0 基础上开发,代码使用链接共享的;
代码已经托管至“码云” ,https://gitee.com/zhcun/ORM
支持数据库: SQL Server 、SQLite、Oracle、MySQL(因为兼容core的统一版本,OleDb目前暂不支持)
大概介绍一下基本功能及环境:
开发工具:VS 2019
开发框架:.Net 4.0 & netstandard2.0
支持Lamda,复杂对象查询
新增与更新:支持自动识别赋值字段
支持数据过滤
支持各操作的方法扩展与重载
支持查看执行详情(SQL、耗时 等)
支持实体类扩展自定义属性
实体类
实体类中做过一些特殊处理,所以放Model的类库也必须引用 ZhCun.DbCore ,并且继承 EntityBase
实体类分 表(视图)和存储过程两种类型,目前视图和表并没有区分开来,对于框架来说表和视图是一样的;
以下为表的实体类
using System;
using ZhCun.DbCore.Entitys;
namespace ZhCun.DbCore.Example.DbModels
{
public partial class TDevice : EntityBase
{
private System.Guid _Id;
/// <summary>
/// Id
/// </summary>
[EntityAttribute(ColumnName = CNId, IsPrimaryKey = true, IsNotNull = true)]
public System.Guid Id
{
get { return _Id; }
set
{
_Id = value;
base.SetFieldChanged(CNId) ;
}
}
private System.String _DevName;
/// <summary>
/// DevName
/// </summary>
[EntityAttribute(ColumnName = CNDevName)]
public System.String DevName
{
get { return _DevName; }
set
{
_DevName = value;
base.SetFieldChanged(CNDevName) ;
}
}
private System.Guid? _DevType;
/// <summary>
/// DevType
/// </summary>
[EntityAttribute(ColumnName = CNDevType)]
public System.Guid? DevType
{
get { return _DevType; }
set
{
_DevType = value;
base.SetFieldChanged(CNDevType) ;
}
}
private System.String _Remark;
/// <summary>
/// Remark
/// </summary>
[EntityAttribute(ColumnName = CNRemark)]
public System.String Remark
{
get { return _Remark; }
set
{
_Remark = value;
base.SetFieldChanged(CNRemark) ;
}
}
private System.DateTime? _CreateTime;
/// <summary>
/// CreateTime
/// </summary>
[EntityAttribute(ColumnName = CNCreateTime)]
public System.DateTime? CreateTime
{
get { return _CreateTime; }
set
{
_CreateTime = value;
base.SetFieldChanged(CNCreateTime) ;
}
}
private System.DateTime? _ModifyTime;
/// <summary>
/// ModifyTime
/// </summary>
[EntityAttribute(ColumnName = CNModifyTime)]
public System.DateTime? ModifyTime
{
get { return _ModifyTime; }
set
{
_ModifyTime = value;
base.SetFieldChanged(CNModifyTime) ;
}
}
private System.Guid? _UserId;
/// <summary>
/// UserId
/// </summary>
[EntityAttribute(ColumnName = CNUserId)]
public System.Guid? UserId
{
get { return _UserId; }
set
{
_UserId = value;
base.SetFieldChanged(CNUserId) ;
}
}
#region 字段名的定义
public const string CNId = "Id";
public const string CNDevName = "DevName";
public const string CNDevType = "DevType";
public const string CNRemark = "Remark";
public const string CNCreateTime = "CreateTime";
public const string CNModifyTime = "ModifyTime";
public const string CNUserId = "UserId";
#endregion
}
}
表实体类中当字段只发生过改变会通过 SetFieldChanged方法处理,它会自动判断字段是否赋值,未赋值的字段不会进行增加与修改
实体类声明了 partial 关键字,当需要扩展一些非表字段的属性时建议使用不同的文件操作,这在实际应用中用处比较多;
实体类自动生成的代码中包含字段名的常量,是为了在特殊情况使用sql查询时尽量用该常量来表示字段名,这样当字段设计发生变化更容易修改对应的代码;
当使用扩展或自定义非表字段的属性时需要标记为 IsNotField = true ,如下
[Entity(IsNotField =true)] public object Tag { set; get; }
其它属性选项:
public class EntityAttribute : Attribute { /// <summary> /// 是否主键 /// </summary> public bool IsPrimaryKey { set; get; } /// <summary> /// 主键是否自动增长 /// </summary> public bool IsIdentity { set; get; } /// <summary> /// 是否非空字段 /// </summary> public bool IsNotNull { set; get; } /// <summary> /// 列名 /// </summary> public string ColumnName { set; get; } /// <summary> /// 默认false为字段属性,如果为true则表示不是一个字段 /// </summary> public bool IsNotField { set; get; } } public class EntiryClassAttribute : Attribute { public string TableName { set; get; } }
存储过程实体类示例:
public class P_AddUser : ProcEntityBase { public string LoginName { set; get; } public string LoginPwd { set; get; } public string UserName { set; get; } [ProcParam(ParamDirection = ParameterDirection.Output)] public string Message { set; get; } [ProcParam(ParamDirection = ParameterDirection.Output)] public bool Success { set; get; } }
存储过程实体类特性定义:
/// <summary> /// 存储过程参数的特性类 /// </summary> public class ProcParamAttribute : Attribute { public ProcParamAttribute() { _ParamDirection = ParameterDirection.Input; _OutSize =50; } public ProcParamAttribute(ParameterDirection paramDirection) { _ParamDirection = paramDirection; } ParameterDirection _ParamDirection; /// <summary> /// 存储过程输出参数的方向类型 /// </summary> public ParameterDirection ParamDirection { get { return _ParamDirection; } set { _ParamDirection = value; } } int _OutSize; /// <summary> /// 输出参数的字节数,默认50个字节 /// </summary> public int OutSize { get { return _OutSize; } set { _OutSize = value; } } /// <summary> /// 是否oracle游标类型 /// </summary> public bool IsOracleCursor { set; get; } /// <summary> /// 参数名,空则使用属性名代表参数名 /// </summary> public string ParameterName { set; get; } /// <summary> /// true表示非存储过程参数 /// </summary> public bool NotParameter { set; get; } }
与表的实体类似,具体可查看备注说明;
实体类是ORM的核心部件,大部分操作都依赖实体类;
数据库上下文(DBContext)
核心类 DBContext ,这与其它orm名称可能有冲突,最早参考的EF起的名字,后来也没变过;
虽然可以直接使用DBContext,但还是建议使用继承他的子类,这也可以重写你想改变或注入的业务逻辑;
早先版本的DBContext 是抽象出的接口,后来经过挺长时间的使用,发现并没有其它实现,所以只用了一个核心的类来实现所有的数据库操作了;
以下为DBContext实现功能列表,具体说明可查看源码或着备注说明
1 // 2 // 摘要: 3 // 数据库操作核心上下文 4 public class DBContext 5 { 6 public DBContext(EmDbType dbType, string connStr); 7 8 // 9 // 摘要: 10 // 数据库操作对象 11 protected internal IDbHelper DbHelper { get; } 12 13 // 14 // 摘要: 15 // 创建查询条件对象,分页、排序; 16 public QueryCondition<TEntity> CreateQuery<TEntity>() where TEntity : EntityBase, new(); 17 // 18 // 摘要: 19 // 创建sql生成器 20 public virtual ISqlBuilder CreateSqlBuilder(); 21 // 22 // 摘要: 23 // 创建指定参数名称前缀的sql生成器(解决参数名称重复) 24 public virtual ISqlBuilder CreateSqlBuilder(string paramKey); 25 // 26 // 摘要: 27 // 创建执行的条件对象,不包含分页、排序 28 public ExecCondition<TEntity> CreateWhere<TEntity>() where TEntity : EntityBase, new(); 29 // 30 // 摘要: 31 // 使用执行条件对象,进行删除表达式 32 // 33 // 参数: 34 // execwhere: 35 // 执行条件对象 36 // 37 // 类型参数: 38 // TEntity: 39 // 实体对象类型 40 // 41 // 返回结果: 42 // 返回执行结果对象 43 public virtual ExecResult Delete<TEntity>(ICondition condition) where TEntity : EntityBase, new(); 44 // 45 // 摘要: 46 // 根据一个基本的表达式进行删除操作 47 // 48 // 参数: 49 // lamda: 50 // 表达式 51 // 52 // 类型参数: 53 // TEntity: 54 // 实体对象类型 55 // 56 // 返回结果: 57 // 返回执行结果对象 58 public virtual ExecResult Delete<TEntity>(Expression<Func<TEntity, bool>> lamda) where TEntity : EntityBase, new(); 59 // 60 // 摘要: 61 // 根据主键删除一条数据 62 public virtual ExecResult Delete<TEntity>(TEntity entity) where TEntity : EntityBase, new(); 63 // 64 // 摘要: 65 // 执行存储过程的方法 66 // 67 // 参数: 68 // procObj: 69 // 存储过程实体对象 70 // 71 // 类型参数: 72 // ProcEntity: 73 // ProcedureEntiryBase 74 // 75 // 返回结果: 76 // 返回存储过程结果 77 public virtual ProcResult ExecProcedure<ProcEntity>(ProcEntity procObj) where ProcEntity : ProcEntityBase, new(); 78 // 79 // 摘要: 80 // 根据sql建造起执行sql语句 81 public virtual ExecResult ExecSql(ISqlBuilder sqlBuilder); 82 // 83 // 摘要: 84 // 新增一条记录 85 public virtual ExecResult Insert<TEntity>(TEntity entity) where TEntity : EntityBase, new(); 86 // 87 // 摘要: 88 // 使用条件对象来进行复杂查询 89 public virtual QueryResult<TEntity> Query<TEntity>(IQueryCondition condition, ISqlBuilder joinWhereBuilder) where TEntity : EntityBase, new(); 90 // 91 // 摘要: 92 // 根据查询对象进行读取数据库,可返回DataTable、List 93 public virtual QueryResult<TEntity> Query<TEntity>(IQueryCondition condition) where TEntity : EntityBase, new(); 94 // 95 // 摘要: 96 // 使用表达式进行普通查询 97 // 98 // 参数: 99 // lamda: 100 // 表达式 101 // 102 // 类型参数: 103 // TEntity: 104 // 实体对象类型 105 public virtual QueryResult<TEntity> Query<TEntity>(Expression<Func<TEntity, bool>> lamda) where TEntity : EntityBase, new(); 106 // 107 // 摘要: 108 // 根据一个sqlBuilder来构造where条件的查询 109 // 110 // 参数: 111 // sqlBuilder: 112 // 可实现参数化查询的sql文本构造器, 不包含 where 113 public virtual QueryResult<TEntity> Query<TEntity>(ISqlBuilder whereSqlBuilder) where TEntity : EntityBase, new(); 114 // 115 // 摘要: 116 // 根据一个sqlBuilder来构造一个完整的查询 117 // 118 // 参数: 119 // sqlBuilder: 120 // 可实现参数化查询的sql文本构造器 121 public virtual QueryResult Query(ISqlBuilder sqlBuilder); 122 public int QueryCount<TEntity>(Expression<Func<TEntity, bool>> lamda) where TEntity : EntityBase, new(); 123 public int QueryCount<TEntity>(IQueryCondition condition) where TEntity : EntityBase, new(); 124 public virtual ScalarResult QueryCountResult<TEntity>(IQueryCondition condition) where TEntity : EntityBase, new(); 125 public virtual ScalarResult QueryCountResult<TEntity>(Expression<Func<TEntity, bool>> lamda) where TEntity : EntityBase, new(); 126 public bool QueryExist<TEntity>(IQueryCondition condition) where TEntity : EntityBase, new(); 127 public bool QueryExist<TEntity>(Expression<Func<TEntity, bool>> lamda) where TEntity : EntityBase, new(); 128 public virtual ScalarResult QueryMax<TEntity>(Expression<Func<TEntity, object>> selector, IQueryCondition condition) where TEntity : EntityBase, new(); 129 // 130 // 摘要: 131 // 执行最大值函数查询 132 public virtual ScalarResult QueryMax<TEntity>(Expression<Func<TEntity, object>> selector, Expression<Func<TEntity, bool>> lamda) where TEntity : EntityBase, new(); 133 public virtual ScalarResult QueryMin<TEntity>(Expression<Func<TEntity, object>> selector, Expression<Func<TEntity, bool>> lamda) where TEntity : EntityBase, new(); 134 public virtual ScalarResult QueryMin<TEntity>(Expression<Func<TEntity, object>> selector, IQueryCondition condition) where TEntity : EntityBase, new(); 135 // 136 // 摘要: 137 // 根据一个sqlBuilder 来构造一个完整的查询,用于获取首行首列值 138 // 139 // 参数: 140 // sqlBuilder: 141 // 可实现参数化查询的sql文本构造器 142 public virtual ScalarResult QueryScalar(ISqlBuilder sqlBuilder); 143 public virtual ScalarResult QuerySum<TEntity>(Expression<Func<TEntity, object>> selector, Expression<Func<TEntity, bool>> lamda) where TEntity : EntityBase, new(); 144 public virtual ScalarResult QuerySum<TEntity>(Expression<Func<TEntity, object>> selector, IQueryCondition condition) where TEntity : EntityBase, new(); 145 // 146 // 摘要: 147 // 事务提交 148 public void TransCommit(); 149 // 150 // 摘要: 151 // 事务回滚 152 public void TransRollback(); 153 // 154 // 摘要: 155 // 事务开始 156 public void TransStart(); 157 // 158 // 摘要: 159 // where对象条件更新 160 public virtual ExecResult Update<TEntity>(TEntity entity, ICondition condition) where TEntity : EntityBase, new(); 161 // 162 // 摘要: 163 // 实体对象更新,主键必填 164 public virtual ExecResult Update<TEntity>(TEntity entity) where TEntity : EntityBase, new(); 165 // 166 // 摘要: 167 // lamda表达式更新 168 public virtual ExecResult Update<TEntity>(TEntity entity, Expression<Func<TEntity, bool>> lamda) where TEntity : EntityBase, new(); 169 // 170 // 摘要: 171 // 当使用sqlbuilder(所有实体类执行的Sql都会触发)进行 更新、删除、查询、并指定具体实体类型时在执行前触发, 用于数据过滤的统一处理; 需要子类重写处理过程 172 protected virtual void BeforeExecSqlBuilder<TEntity>(ISqlBuilder sqlBuilder, EmDbOperation opType) where TEntity : EntityBase, new(); 173 // 174 // 摘要: 175 // 创建基于实体形参的where条件的sqlBuider对象(共通封装) 176 protected virtual ISqlBuilder CreateQuerySqlBuilder<TEntity>() where TEntity : EntityBase, new(); 177 // 178 // 摘要: 179 // 使用表达式删除的老大 180 protected virtual ExecResult DeleteBase<TEntity>(Func<ISqlBuilder, string> whereFun) where TEntity : EntityBase, new(); 181 // 182 // 摘要: 183 // 根据sql建造起执行sql语句,加上执行sql where文本 184 protected virtual ExecResult ExecSql(ISqlBuilder sqlBuilder, string sqlWhere); 185 // 186 // 摘要: 187 // 获取实体对象值,不忽略主键值 188 protected Dictionary<string, object> GetEntityValue<TEntity>(TEntity entity) where TEntity : EntityBase, new(); 189 // 190 // 摘要: 191 // 获取属性值,指定是否忽略自增长主键 192 protected Dictionary<string, object> GetEntityValue<TEntity>(TEntity entity, bool ignorePK) where TEntity : EntityBase, new(); 193 // 194 // 摘要: 195 // 更新的老大 196 protected virtual ExecResult UpdateBase<TEntity>(TEntity entity, Func<ISqlBuilder, string> whereFun) where TEntity : EntityBase, new(); 197 }