大型项目中ORM的使用已经是相当的频繁。目前.NET(C#)中比较流行的ORM框架也有很多,比如SqlSugar,Dapper,Entity Framework(EF)等。

相信很多有2年以上工作经验的园友都会使用其中一种或者几种。同时多多少少也会存在有会用却不懂其中原理的园友(我算其中一个),所以凭借

工作之余独自钻研了一段时间,现在分享下我的钻研成果。  同时也希望园内大能者指出不足之处。

在工作中,本人觉得写SQL 查询数据还是挺方便。所以这个轻量级的ORM中对于查询还是使用写SQL的方式

下图就是主要的文件:

DataFieldAttribute.cs:实体映射表字段 特性(用于标注实体类中成员属性对应数据库中的字段名和字段类型)

PropertyAttribute.cs  :实体映射数据库表 特性(用于标注实体类对应数据库中哪个表)

DBCrateFactory.cs    :创建数据库对象的工厂(用于创建哪种数据库对象   MS SQL   还是  ORACLE)

SQLHelper.cs            :这是一个抽象函数。DBWorks文件夹下所有类都继承该抽象函数,这些子类就必须实现SQLHelper中的抽象方法同时也可以使用该抽象函数的公用方法

IWiteem.cs                : 对外接口

Witeem.cs       :继承并实现IWiteem接口

CommonHelper.cs     :通用工具类

DBWorks文件夹下存放的是数据库操作类(因为是DEMO,所以只设置了MS SQL和ORACLE)

Enum文件夹下存放的是需要使用到的一些枚举类(ColumnKeyType.cs  字段状态, DBEnum.cs 数据库类型)

下图是接口中提供的方法:

下载地址中的代码或许还存在少部分瑕疵,在每次发现并更改过程后我及时更新。

2018-06-26 Bug:

1、SQLHelper类的ExecuteQueryPage函数

2、CommonHelper类的 DataTableToObject<T> 和 DataTableToList<T>修改成根据DataFieldAttribute特性中的字段反射对应的值

public static T DataTableToObject<T>(DataTable dt, bool IsDataField) where T : new()
{
Type type = typeof(T);
string tempName = string.Empty;
T myt = new T();
PropertyInfo[] propertys = myt.GetType().GetProperties();
PropertyInfo[] array = propertys;
int i = ;
DataFieldAttribute attribute = null;
PropertyAttribute proAttribute = null;
while (i < array.Length)
{
PropertyInfo pi = array[i];
if (IsDataField)
{
object[] infos = null;
object[] pros = null;
infos = pi.GetCustomAttributes(typeof(DataFieldAttribute), false);
pros = pi.GetCustomAttributes(typeof(PropertyAttribute), false);
if (infos.Length > )
{
attribute = (DataFieldAttribute)(infos[]);
if (pros.Length>)
{
proAttribute = (PropertyAttribute)(pros[]);
if (proAttribute.columnKeyType != ColumnKeyType.Extend)
{
tempName = attribute.FieldName;
}
}else
tempName = attribute.FieldName;
}
}
else
tempName = pi.Name; if (dt.Columns.Contains(tempName))
{
if (pi.CanWrite)
{
object value = dt.Rows[][tempName];
if (value.GetType().Equals(typeof(DateTime)))
value = Convert.ToString(value);
if (value != DBNull.Value)
pi.SetValue(myt, value, null);
}
}
i += ;
continue;
}
return myt;
}
public static List<T> DataTableToList<T>(DataTable dt, bool IsDataField) where T : new()
{
List<T> ts = new List<T>();
Type type = typeof(T);
string tempName = string.Empty;
foreach (DataRow dr in dt.Rows)
{
T myt = new T();
PropertyInfo[] propertys = myt.GetType().GetProperties();
PropertyInfo[] array = propertys;
int i = ;
DataFieldAttribute attribute = null;
PropertyAttribute proAttribute = null;
while (i < array.Length)
{
PropertyInfo pi = array[i];
if (IsDataField)
{
object[] infos = null;
object[] pros = null;
infos = pi.GetCustomAttributes(typeof(DataFieldAttribute), false);
pros = pi.GetCustomAttributes(typeof(PropertyAttribute), false);
if (infos.Length > )
{
attribute = (DataFieldAttribute)(infos[]);
if (pros.Length > )
{
proAttribute = (PropertyAttribute)(pros[]);
if (proAttribute.columnKeyType != ColumnKeyType.Extend)
{
tempName = attribute.FieldName;
}
}
else
tempName = attribute.FieldName;
}
}
else
tempName = pi.Name;
if (dt.Columns.Contains(tempName))
{
if (pi.CanWrite)
{
object value = dr[tempName];
if (value.GetType().Equals(typeof(DateTime)))
value = System.Convert.ToString(value);
if (value != DBNull.Value)
pi.SetValue(myt, value, null);
}
}
i += ;
continue;
}
ts.Add(myt);
}
return ts;
}

2018-06-28 Bug:反射实体获取表字段时不是去特性中标注的字段名(现已修复)

1、修改工具类中的GetTableColumns函数(注释部分为旧的代码),GetTableColumns函数也做了相应的修改

public static List<string> GetTableColumns(PropertyInfo[] pis, ref List<PropertyInfo> proList, bool Isidentity = false)
{
List<string> columns = new List<string>();
object[] infos = null;
object[] fields = null;
DataFieldAttribute Fieldattribute = null;
PropertyAttribute attribute = null;
foreach (PropertyInfo pi in pis)
{
//获取此成员所有自定义特性
infos = pi.GetCustomAttributes(typeof(PropertyAttribute),false);
fields = pi.GetCustomAttributes(typeof(DataFieldAttribute), false);
if (fields.Length == )
{
continue;
}
Fieldattribute = (DataFieldAttribute)(fields[]);
if (infos.Length > )
{
attribute = (PropertyAttribute)(infos[]);
if (attribute == null)
{
//columns.Add(pi.Name);
columns.Add(Fieldattribute.FieldName);
proList.Add(pi);
}
else
{
switch (attribute.columnKeyType)
{
case ColumnKeyType.Extend: break;
case ColumnKeyType.Identity:
{
if (Isidentity)
{
//columns.Add(pi.Name);
columns.Add(Fieldattribute.FieldName);
proList.Add(pi);
}
}; break;
default:
{
//columns.Add(pi.Name);
columns.Add(Fieldattribute.FieldName);
proList.Add(pi);
};
break;
}
}
}
}
return columns;
}

2、MSSql.cs类 对于上述BUG做了修改

public override int Add<T>(IEnumerable<T> obj)
{
try
{
int i = ;
int result = ;
int success = ;
//Type type = obj.GetType();
Type type = typeof(T);
//获取表名
string tableName = CommonHelper.GetTableName(type);
PropertyInfo[] pis = type.GetProperties();
//获取所有字段,和主键名称
List<string> columns = null;
List<PropertyInfo> proList = new List<PropertyInfo>();
columns = CommonHelper.GetTableColumns(pis,ref proList, false);
//处理是否包含主键插入
//if (isIdentity)
//{
// columns = CommonHelper.GetTableColumns(pis, true);
//}
//else
//{
// columns = CommonHelper.GetTableColumns(pis, false);
//}
foreach (T item in obj)
{
//生成SQL语句
StringBuilder sqlText = new StringBuilder();
sqlText.Append(" INSERT INTO ");
sqlText.Append(tableName);
sqlText.Append(" (");
//第一个字段
sqlText.Append(columns[]);
//第二个起所有字段
int loop = columns.Count;
for (i = ; i < loop; i++)
{
sqlText.Append(",");
sqlText.Append(columns[i]);
}
sqlText.Append(") VALUES (");
//第一个字段
sqlText.Append("@");
sqlText.Append(columns[]);
//第二个起所有字段
for (i = ; i < loop; i++)
{
sqlText.Append(",@");
sqlText.Append(columns[i]);
}
sqlText.Append(");");
//生成SqlParamter
PropertyInfo propertyInfo = null;
List<SqlParameter> paras = new List<SqlParameter>();
for (i = ; i < loop; i++)
{
propertyInfo = proList[i];
SqlParameter para = new SqlParameter(columns[i], CommonHelper.GetSqlType(propertyInfo.PropertyType), -);
para.Value = propertyInfo.GetValue(item);
paras.Add(para);
}
result = ExecuteNonQuery(sqlText.ToString(), CommandType.Text, paras, false);
if (result > )
{
success += ;
}
}
if (conn.State == ConnectionState.Open)
{
ConColsed();
}
return success; }
catch (Exception ex)
{
execlog.Debug(DateTime.Now.ToString() + ": Add失败,原因【" + ex.ToString() + "】");
return -;
}
}
public override int Delete<T>(IEnumerable<T> obj)
{
try
{
int result = ;
int success = ;
//Type type = obj.GetType();
Type type = typeof(T);
//获取表名
string tableName = CommonHelper.GetTableName(type);
PropertyInfo[] pis = type.GetProperties();
PropertyInfo identityInfo = null;
identityInfo = CommonHelper.GetTableIdentity(pis);
string identityName = CommonHelper.GetIdentityName(pis);
if (identityInfo == null)
{
return ;
}
if (string.IsNullOrEmpty(identityName))
{
identityName = identityInfo.Name;
}
foreach (T item in obj)
{
//生成SQL语句
StringBuilder sqlText = new StringBuilder();
sqlText.Append(" DELETE FROM ");
sqlText.Append(tableName);
sqlText.Append(" WHERE 1=1 ");
//主键筛选
sqlText.Append(" AND " + identityName);
sqlText.Append("=@" + identityName);
//生成SqlParamter
List<SqlParameter> paras = new List<SqlParameter>();
SqlParameter para = new SqlParameter(identityName, CommonHelper.GetSqlType(identityInfo.PropertyType), -);
para.Value = identityInfo.GetValue(item);
paras.Add(para);
result = ExecuteNonQuery(sqlText.ToString(), CommandType.Text, paras,false);
if (result>)
{
success += ;
}
}
if (conn.State == ConnectionState.Open)
{
ConColsed();
}
return success;
}
catch (Exception ex)
{
execlog.Debug(DateTime.Now.ToString() + ": Delete失败,原因【" + ex.ToString() + "】");
return -;
}
}
public override int Update<T>(IEnumerable<T> obj)
{
try
{
int i = ;
int result = ;
int success = ;
//Type type = obj.GetType();
Type type = typeof(T);
//获取表名
string tableName = CommonHelper.GetTableName(type);
PropertyInfo[] pis = type.GetProperties();
//获取所有字段,和主键名称
string identityName = CommonHelper.GetIdentityName(pis);
//获取主键名称
PropertyInfo identityInfo = null;
identityInfo = CommonHelper.GetTableIdentity(pis);
if (identityInfo == null)
{
return ;
}
if (string.IsNullOrEmpty(identityName))
{
identityName = identityInfo.Name;
}
List<string> columns = null;
List<PropertyInfo> proList = new List<PropertyInfo>();
//获取所有字段名称
columns = CommonHelper.GetTableColumns(pis, ref proList, true);
foreach (T item in obj)
{
//生成SQL语句
StringBuilder sqlText = new StringBuilder();
int loop = columns.Count;
sqlText.Append(" UPDATE ");
sqlText.Append(tableName);
sqlText.Append(" SET ");
//第二个起所有字段
for (i = ; i < loop; i++)
{
//判断第一个字段是否为主键
if (columns[i] == identityName)
{
continue;
}
sqlText.Append(columns[i] + "=@" + columns[i]);
if (i < loop - )
{
sqlText.Append(",");
}
}
//主键筛选
sqlText.Append(" WHERE " + identityName);
sqlText.Append("=@" + identityName);
//生成SqlParamter
List<SqlParameter> paras = new List<SqlParameter>();
PropertyInfo propertyInfo = null;
for (i = ; i < loop; i++)
{
propertyInfo = proList[i];
SqlParameter para = new SqlParameter(columns[i], CommonHelper.GetSqlType(propertyInfo.PropertyType), -);
para.Value = propertyInfo.GetValue(item);
paras.Add(para);
}
result = ExecuteNonQuery(sqlText.ToString(), CommandType.Text, paras,false);
if (result>)
{
success += ;
}
}
if (conn.State == ConnectionState.Open)
{
ConColsed();
}
return success;
}
catch (Exception ex)
{
execlog.Debug(DateTime.Now.ToString() + ": Update失败,原因【" + ex.ToString() + "】");
return -;
} }
public override T GetModel<T>(string id)
{
int i = ;
Type type = typeof(T);
T myT = new T();
//获取表名
string tableName = CommonHelper.GetTableName(type); PropertyInfo[] pis = type.GetProperties();
PropertyInfo identityInfo = null;
identityInfo = CommonHelper.GetTableIdentity(pis);
string identityName = CommonHelper.GetIdentityName(pis);
if (identityInfo == null)
{
return default(T);
}
if (string.IsNullOrEmpty(identityName))
{
identityName = identityInfo.Name;
}
//获取所有字段,和主键名称
List<string> columns = null;
List<PropertyInfo> proList = new List<PropertyInfo>();
//获取所有字段名称
List<ColumnKeyType> filterList = new List<ColumnKeyType>();
filterList.Add(ColumnKeyType.Default);
filterList.Add(ColumnKeyType.Read);
filterList.Add(ColumnKeyType.Identity);
columns = CommonHelper.GetTableColumns(pis, ref proList, true);
//生成SQL语句
StringBuilder sqlText = new StringBuilder();
sqlText.Append(" SELECT ");
//第一个字段
sqlText.Append(columns[]);
//第二个起所有字段
int loop = columns.Count;
for (i = ; i < loop; i++)
{
sqlText.Append(",");
sqlText.Append(columns[i]);
}
sqlText.Append(" FROM ");
sqlText.Append(tableName);
sqlText.Append(" WHERE 1=1 AND ");
sqlText.Append(identityName + "=@" + identityName);
//生成SqlParamter
List<SqlParameter> paras = new List<SqlParameter>();
SqlParameter para = new SqlParameter(identityName, CommonHelper.GetSqlType(identityInfo.PropertyType), -);
para.Value = id;
paras.Add(para);
return GetModel<T>(sqlText.ToString(), CommandType.Text, paras);
}

3、事务处理应先打开数据库连接

2018-12-13 获取所有字段名称的地方加入缓存机制,目的是避免每次执行都需要去获取字段名称数据集,提高效率:

Update 和 GetModel 方法的缓存机制

//获取所有字段名称(缓存处理)
if (CacheHelper.GetCache(tableName) != null)
{
columns = (List<string>)CacheHelper.GetCache(tableName);
}
else
{
columns = CommonHelper.GetTableColumns(pis, ref proList, true);
CacheHelper.SetCache(tableName, columns, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes());
}

Add方法的缓存机制:

 //获取所有字段名称(缓存处理)
if (CacheHelper.GetCache(tableName + isIdentity.ToString()) != null)
{
columns = (List<string>)CacheHelper.GetCache(tableName + isIdentity.ToString());
}
else
{
columns = CommonHelper.GetTableColumns(pis, ref proList, isIdentity);
CacheHelper.SetCache(tableName + isIdentity.ToString(), columns, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes());
}

github下载地址:https://github.com/witeem/ASP.NET-ORM.git

asp.net—自定义轻量级ORM的更多相关文章

  1. 连表查询都用Left Join吧 以Windows服务方式运行.NET Core程序 HTTP和HTTPS的区别 ASP.NET SignalR介绍 asp.net—WebApi跨域 asp.net—自定义轻量级ORM C#之23中设计模式

    连表查询都用Left Join吧   最近看同事的代码,SQL连表查询的时候很多时候用的是Inner Join,而我觉得对我们的业务而言,99.9%都应该使用Left Join(还有0.1%我不知道在 ...

  2. 自己开发轻量级ORM(一)

    在开发ORM之前,先简单的介绍下ORM的基本概念. 对象关系映射(Object Relational Mapping,简称ORM)是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术. 简单的 ...

  3. .NET轻量级ORM组件Dapper修炼手册

    一.摘要 1.1.为什么叫本次的分享课叫<修炼手册>? 阿笨希望本次的分享课中涉及覆盖的一些小技巧.小技能给您带来一些帮助.希望您在日后工作中把它作为一本实际技能手册进行储备,以备不时之需 ...

  4. Farseer.net轻量级ORM开源框架 V1.x 教程目录

    本篇教程将以Ver 1.x版本进行详细使用讲解 大家有任何疑问可以加入我们的官方QQ群进行讨论.QQ群:116228666 (Farseer.net开源框架交流) 请注明:Farseer.Net 整个 ...

  5. Farseer.net轻量级ORM开源框架 V1.x 入门篇:数据库上下文

    导航 目   录:Farseer.net轻量级ORM开源框架 目录 上一篇:Farseer.net轻量级ORM开源框架 V1.x 入门篇:数据库配置文件 下一篇:Farseer.net轻量级ORM开源 ...

  6. 轻量级ORM框架初探-Dapper与PetaPoco的基本使用

    一.EntityFramework EF是传统的ORM框架,也是一个比较重量级的ORM框架.这里仍然使用EF的原因在于为了突出轻量级ORM框架的性能,所谓有对比才有更优的选择. 1.1 准备一张数据库 ...

  7. c# 轻量级ORM框架 实现(一)

    发布一个自己写的一个轻量级ORM框架,本框架设计期初基于三层架构.所以从命名上来看,了解三层的朋友会很好理解. 设计该框架的目的:不想重复的写增删改查,把精力放到功能实现上. 发布改框架的原因:希望给 ...

  8. ASP.NET自定义错误页面

    ASP.NET自定义错误页面 ASP.NET 提供三种用于在出现错误时捕获和响应错误的主要方法:Page_Error 事件.Application_Error 事件以及应用程序配置文件 (Web.co ...

  9. 自己开发轻量级ORM(二)

    上一篇简单的对轻量级ORM开发开了个头.这篇主要聊下ORM框架的设计思路. ORM本质上是对数据库操作的抽象.大体上我将其分为对数据结构的抽象和对执行方法的抽象. 我的ORM设计图: ORM框架需要完 ...

随机推荐

  1. 删除排序数组中的重复数字 II · Remove Duplicates from Sorted Array II

    重复一次 [抄题]: 给定一个排序数组,在原数组中删除重复出现的数字,使得每个元素只出现一次,并且返回新的数组的长度. 不要使用额外的数组空间,必须在原地没有额外空间的条件下完成. [思维问题]: [ ...

  2. Linux之常用命令

    1.cd命令 这是一个非常基本,也是大家经常需要使用的命令,它用于切换当前目录,它的参数是要切换到的目录的路径,可以是绝对路径,也可以是相对路径.如: cd /root/Docements # 切换到 ...

  3. 通过dockerfile构建nginx

    上次 利用命令行的形式来构建nginx服务, http://www.cnblogs.com/loveyouyou616/p/6806788.html 这次利用dockerfile文件来构建nginx服 ...

  4. [BAT]远程执行或停止计划任务

    执行 schtasks /run /tn "IPADForAdvisor_QA_APITest" /s SZPCWIN2K801 /u msdomain1\jzhang6 /p j ...

  5. Debian8 下面 muduo库编译与使用

    其实<Linux 多线程服务端编程>已经写得很详细 但是考虑到代码版本的更新和操作系统的不同 可能部分位置会有些许出入 这里做个记录 方便以后学习运行 我使用的虚拟 安装的是debian系 ...

  6. RSA生成、加密、解密、签名。

    首先,要会生成RSA密码对. https://app.alipay.com/market/document.htm?name=saomazhifu#page-23    (事例中的密钥对好像有问题,最 ...

  7. win 控制台工作路径切换

    1.如果是同磁盘 直接cd 列如cd C:\mysql\bin 2.如果不是同一磁盘 则要2.1 d: 操作 2.2 cd D:\Software\xampp\address\mysql\bin ps ...

  8. docker 部署nginx 使用keepalived 部署高可用

    一.体系架构 在Keepalived + Nginx高可用负载均衡架构中,keepalived负责实现High-availability (HA) 功能控制前端机VIP(虚拟网络地址),当有设备发生故 ...

  9. Part 1 - Getting Started(1-3)

    https://simpleisbetterthancomplex.com/series/2017/09/04/a-complete-beginners-guide-to-django-part-1. ...

  10. sql join用法(转)

    left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录inner join(等值连接) 只 ...