Object Relational Mapping(对象关系映射),其中最重要的就是这个映射Mapping。通俗点说就是把直接操作数据库的那一套,直接搬到利用面向对象的思想,我们通过直接操作对象来间接达到操作数据库的目的。底层都是ado.net
ORM底层实战(crud) Find(int id)(查询)(基础版本)具体根据什么字段查询传参数可以自己定义
public T Find(int id) where T : BaseEntity { //通过泛型+反射 达到通用的目的 Type type = typeof(T);//f反射类 //拼接每一个字段 select 字段 from 表名字 string column = string.Join(",", type.GetProperties().Select(prop => prop.Name)); //拼接基础字符串 string sqlString = $"select {column} from {type.Name} where id={id}"; //连接数据库 using (SqlConnection conn = new SqlConnection("Data Source=PC04E0010016\MSSQLSERVER01;Initial Catalog=ZHIBO; User Id=niubi;Password=123456")) { SqlCommand command = new SqlCommand(sqlString,conn); conn.Open();//打开数据库 var reader=command.ExecuteReader(); if (reader.Read()) { T t = (T) Activator.CreateInstance(type);//反射创建对象 //反射便利对象得到字段 foreach (var prop in type.GetProperties()) { prop.SetValue(t, reader[prop.Name]); } return t; } else { return default(T); } }
public interface BaseEntity
{
}
public class Program
{
public static void Main(string[] args)
{
DateHelper helper = new DateHelper();
var entity=helper.Find(1);
}
}
这样直接运行的话呢或报错,原因就是查询出来的字段是null,但是映射到类中就是DBNull,所以这里要加上dbnull的过滤
prop.SetValue(t, reader[prop.Name] is DBNull? null : reader[prop.Name]);Find(int id)(查询)(升级版本)
在以上代码不变的基础之上做功能增加,因为在实际开发当中啊,一定会遇到,类名和数据库标明不一致的问题,还有字段和类的属性名字也不一致,在很多的orm框架当中,经常会加一个特性来解决,这一点我们也来实现一下。
这里就要用到特性
新建一个特性tablename
[AttributeUsage(AttributeTargets.Class)]//作用在类上面
public class TableNameAttribute:Attribute
{
private string name { get; set; }
public TableName(string name)
{
this.name = name;
}
///
/// 对外提供一个方法,到时候反射特性的时候获取name
///
///
public string GetName()
{
return this.name;
}
}
在基础版本上面,我们只要获取类名和字段名的时候,判断有没有呗标记特性,有的话直接取特性里面的name不就好了
来实现一下
对type增加一个扩展方法,专门获取特性里面的name
public static class ORMExtension
{
public static string GetTableName(this Type type)
{
if (type.IsDefined(typeof(TableNameAttribute), true))//判断有没有这个特性
{
//得到这个特性
var attribute= type.GetCustomAttribute();
return attribute.GetName();
}
else
{//没有标记直接返回类名
return type.Name;
}
}
}
在最上面的版本里面只要修改一句话
type.Name 改成 type.GetTableName()
//拼接基础字符串
string sqlString = $"select {column} from {type.GetTableName()} where id={id}";
对于属性名不一致一样的道理
从上面两个版本就看出为什么有人说orm框架性能不如原生ado.net,其实从代码就看出来了,大量的反射,而且一旦出现特性的问题就会不停的反射,所以导致性能缺失,那就想办法解决呗
在上面中看出其实消耗性能的就是反射,而且都是重复性的工作,那能不能只能重复性的工作只做一次,就好了,这里就用到泛型缓存了。
可以建立一个静态类的泛型来实现
就是这边消耗性能,把他给缓存起来
//通过泛型+反射 达到通用的目的
Type type = typeof(T);//f反射类
//拼接每一个字段 select 字段 from 表名字
string column = string.Join(",", type.GetProperties().Select(prop => prop.Name));
//拼接基础字符串
string sqlString = $"select {column} from {type.GetTableName()} where id={id}";
具体实现方法
public class SqlBuilderwhere T : BaseEntity { private static string _finSql = null; static SqlBuilder() { Type type = typeof(T); { string columnsString = string.Empty; _finSql = $"select {columnsString} from [{type.GetTableName()}] where id= "; } } /// /// 以Id= 结尾,可以直接添加参数 /// ///public static string GetFindSql() { return _finSql; } }
把实现放在静态构造函数里面,每次返回会自动实现,而且一单执行一次下次就不会再去执行,包括T变化的时候也是执行一次
后续还会增加事务等操作



