今天就跟大家聊聊有关使用c# 怎么编写一个ORM框架,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。
1. ORM
ORM全称 Object Relational Mapping,翻译过来就是对象关系映射。是一种通过描述对象与数据库之间映射关系的数据,将对象保存到数据库中的技术。
在C#中,曾经Entity Framework光芒万丈,遮盖了其他ORM框架的光辉(甚至如今都是如此)。
后来慢慢涌现除了其他的一些ORM框架,进一步丰富了市场。所以现有比较流行的大概有以下几种:
Dapper 一个轻量的ORM框架
Entity Framework/Entity Framework Core 功能完备的框架
Nhibernate Java平台上著名的Hibernate的.net版
等等
嗯,这是我最近找到的创作组还在更新的几个框架,当然还有其他的很多有趣好用的ORM框架。欢迎各位补充哈。
这一篇的主要目的不是介绍这些框架(这是以后的内容),而是通过我们自己实现一个类ORM框架来了解底层核心。
2. 设计
我们先分析一下,如果我们设计一个实体对象与数据库之间转换的工具类应该具有哪些功能?
一个属性与数据库字段的映射关系
增删改查的SQL模板
查询结果与对象的转换
3. 实现
首先,声明一个类,因为不能仅支持一种类型,所以这个类的所有与数据库有关的方法都是泛型方法,或者这个类是泛型类,所以定义为泛型类:
public class OrmUtil<T>{}
我们事先约定类名即表名,属性名即表的列名,所以我们可以快速得到以下内容:
/// <summary>/// T的类型实例/// </summary>private Type dType;/// <summary>/// T的属性表/// </summary>private PropertyInfo[] properties;public OrmUtil(){ dType = typeof(T); properties = dType.GetProperties();}
声明一个数据库连接:
public SqlConnection Connection { get; set; }
创建一个私有方法,检查连接是否可用:
/// <summary>/// 检查连接是否可用/// </summary>/// <returns></returns>private bool CheckConnection(){ return Connection?.State == ConnectionState.Open;}
准备工作完成,然后开始编写具体的业务方法:
Insert:
public int Insert(T entity){ if (!CheckConnection()) return -1;// 检查状态 var insert = $"insert into {dType.Name}({string.Join(",", properties.Select(t => t.Name))})"; var values = properties.Select(p => p.GetValue(entity)); var commandText = $"{insert} values('{string.Join("','", values)}')"; var command = Connection.CreateCommand(); command.CommandText = commandText; var result = command.ExecuteNonQuery(); return result;}
首先按照属性名与列名之间的映射拼接 SQL,然后执行SQL命令。
Update:
public int Update(T entity,string keyName,object keyValue){ if (!CheckConnection()) return -1; var setValues = properties.ToDictionary(p => p.Name, p => $"'{p.GetValue(entity)}'"); var setSql = string.Join(",", setValues.Select(pair=>$"{pair.Key}='{pair.Value}'")); var sql = $"update {dType.Name} set {setSql} where {keyName} = '{keyValue}'"; var command = Connection.CreateCommand(); command.CommandText = sql; return command.ExecuteNonQuery();}
Update需要注意的就是如何正确拼接赋值sql。
Delete:
删除满足条件的对象:
public int Delete(T entity){ if (!CheckConnection()) return -1; var querySet = properties.Select(p => $"{p.Name} = '{p.GetValue(entity)}'"); var sql = $"delete from {dType.Name} where {string.Join(" and ", querySet)}"; var command = Connection.CreateCommand(); command.CommandText = sql; return command.ExecuteNonQuery();}
这里写法有时候根据实际业务不同,大多数情况下删除主键对应的元素,或者满足某一个条件的所有元素。这里只是做了个演示,小伙伴们可以试试自己改造一下。
Search:
先创建一个从DataTable转成对象的工具方法:
private List<T> Convert(DataTable table){ var list = new List<T>(table.Rows.Count);//事先声明一下容量 foreach(DataRow row in table.AsEnumerable()) { T entity = Activator.CreateInstance<T>(); foreach(var p in properties) { if (!table.Columns.Contains(p.Name)) continue;// 如果属性名不在表格中,则忽略 p.SetValue(entity, row[p.Name]); } list.Add(entity); } return list;}
好,我们写一个查询方法:
public List<T> SearchAll(){ var adapter = new SqlDataAdapter($"select * from {dType.Name}", Connection); var set = new DataSet(); adapter.Fill(set); return Convert(set.Tables[0]);}
这样一个简单的ORM框架就这样形成雏形了,当然实际上的ORM底层比这复杂,因为需要支持不同的数据库,所以Connection 就不能简简单单的是一个SqlConnection了,或者底层不是像我们一样取巧使用DataTable了。
实际上的DataTable到类对象的转换要比我写的复杂一点,因为还要判断这个属性是否是可读、可写的。
看完上述内容,你们对使用c# 怎么编写一个ORM框架有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注编程网行业资讯频道,感谢大家的支持。