前言:
在使用各种的orm框架的过程中,菜鸟的我始终没有搞懂底层实现技术,最近刚好没事找了些视频和资料了解一点皮毛,想记录下,大家勿喷。
所谓的ORM(Object Relational Mapping) 对象关系映射 官方解释是通过使用描述对象和数据库之间映射的元数据,将面向对象程序的对象自动持久化到关系数据库中。
个人理解就是一个数据库访问的帮助类,可以让我们不用手写sql,就完成数据库的访问
使用的技术: 泛型、反射、特性、扩展
摸索步骤:
step1
新建项目,建几个类库,大家熟悉的三层。
step2:
在数据访问层新建一个sqlhelper 类;
2.1 添加一个数据查询的方法,还需要添加model层添加SysUser,完成实体与表映射,实现代码 如下

1 public class SysUser
2 {
3 public long Id { get; set; }
4 public string Login_Name { get; set; }
5 public string Name { get; set; }
6 public string Icon { get; set; }
7 public string Password { get; set; }
8 public string Salt { get; set; }
9 public string Tel { get; set; }
10 public string Email { get; set; }
11 public SByte Locked { get; set; }
12 public DateTime Create_Date { get; set; }
13 public long Create_By { get; set; }
14 public DateTime Update_Date { get; set; }
15 public long Update_By { get; set; }
16 public string Remarks { get; set; }
17 public SByte Del_Flag { get; set; }
18 }

1 public SysUser QueryUser(string id)
2 {
3 Type type = typeof(SysUser);
4 SysUser sysUser = new SysUser();
5 using (var con = new MySqlConnection(strConnection))
6 {
7 con.Open();
8 string strSql = $"select Id,Login_Name,nick_name,Icon,Password,Salt,Tel,Email,Locked,Create_Date,Create_By,Update_Date,Update_By,Remarks,Del_Flag from sys_user wherer id={id}";
9 MySqlCommand sqlCommand = new MySqlCommand(strSql, con);
10
11 MySqlDataReader mySqlDataReader = sqlCommand.ExecuteReader();
12
13 if(mySqlDataReader.Read())
14 {
15 if (mySqlDataReader.Read())
16 {
17 foreach (var item in type.GetProperties())
18 {
19 item.SetValue(sysUser, mySqlDataReader[item.Name] is DBNull ? null : mySqlDataReader[item.Name]);
20 }
21 }
22
23 }
24
25 }
26
27 return sysUser;
28 }
2.2 上述代码只能对一个表进行查询,需要满足不同表查询可以使用泛型
a. 反射完成动态sql的拼接
Type type=typeof(T);
string tableNam=type.Name;
string colums=string.join(",",type.GetProperties().Select(p=>$"{p.Name}"));string strSql = $"select {colums} from {tableName} where id={id}";
b.ado.net 完成数据库查询
c.反射完成数据动态绑定
e.可空值类型处理
实现代码

1 public T QueryById<T>(string id)
2 {
3 Type type = typeof(T);
4
5 T t = Activator.CreateInstance<T>();//创建实体
6 string tableName = type.Name;
7 string colums = string.Join(",", type.GetProperties().Select(p => $"{p.Name}"));//拼接查询字段
8
9 using (var con = new MySqlConnection(strConnection))
10 {
11 con.Open();
12 string strSql = $"select {colums} from {tableName} where id={id}";
13
14 MySqlCommand sqlCommand = new MySqlCommand(strSql, con);
15 MySqlDataReader mySqlDataReader = sqlCommand.ExecuteReader();
16
17 if (mySqlDataReader.Read())
18 {
19 foreach (var item in type.GetProperties())
20 {
21 item.SetValue(t, mySqlDataReader[item.Name] is DBNull ? null : mySqlDataReader[item.Name]);//需要添加Null 判断
22 }
23 return t;
24 }
25 else
26 {
27 return default(T);
28 }
29 }
30 }
存在问题: 实体类名与数据库表名不一致、实体属性名与数据表字段名不一致
解决上面两个问题 可以使用特性(解释: 特性本质就是一个类,间接或直接继承Attribute 就是一个特性,其为目标元素提供关联的附加信息,并在运行时以反射的方式来获取附加信息)
相关代码如下
抽象类

1 public abstract class AbstractMappingAttribute: Attribute
2 {
3 private string _mappingName;
4
5 public AbstractMappingAttribute(string mappingName)
6 {
7 this._mappingName = mappingName;
8 }
9
10 public string GetMappingName()
11 {
12 return this._mappingName;
13 }
14 }
实体类名与表名不一致时

1 [AttributeUsage(AttributeTargets.Class)]
2 public class MappingTableAttribute : AbstractMappingAttribute
3 {
4 public MappingTableAttribute(string tableName) : base(tableName)
5 {
6
7 }
8 }
实体属性与表字段不一致时

1 [AttributeUsage(AttributeTargets.Property)]
2 public class MappingColumAttribute : AbstractMappingAttribute
3 {
4 public MappingColumAttribute(string colName) : base(colName)
5 {
6
7 }
8 }
注意: 在使用特性须加上本特性类作用的范围,简单理解就是用在类上面还是类的属性或行为上。
实体类使用自定义特性代码如下

1 [MappingTableAttribute("sys_user")]
2 public class SysUser
3 {
4 public long Id { get; set; }
5 public string Login_Name { get; set; }
6 [MappingColumAttribute("nick_name")]
7 public string Name { get; set; }
8 public string Icon { get; set; }
9 public string Password { get; set; }
10 public string Salt { get; set; }
11 public string Tel { get; set; }
12 public string Email { get; set; }
13 public SByte Locked { get; set; }
14 public DateTime Create_Date { get; set; }
15 public long Create_By { get; set; }
16 public DateTime Update_Date { get; set; }
17 public long Update_By { get; set; }
18 public string Remarks { get; set; }
19 public SByte Del_Flag { get; set; }
20 }
怎么获取实体的自定义特性描述的信息?
这里面需要用到扩展方法

1 public static class MappingAttributeExtend
2 {
3 public static string GetMappingName<T>(this T t) where T : MemberInfo
4 {
5 if (t.IsDefined(typeof(AbstractMappingAttribute), true))
6 {
7 AbstractMappingAttribute abstractMappingAttribute = t.GetCustomAttribute<AbstractMappingAttribute>();
8 return abstractMappingAttribute.GetMappingName();
9 }
10 else
11 {
12 return t.Name;
13 }
14 }
15 }
2.3 经过2.2一步步优化最终通用查询方法代码如下

1 public T QueryById<T>(string id)
2 {
3 Type type = typeof(T);
4
5 T t = Activator.CreateInstance<T>();//创建实体
6 string tableName = type.GetMappingName();
7 string colums = string.Join(",", type.GetProperties().Select(p => $"{p.GetMappingName()}"));//拼接查询字段
8
9 using (var con = new MySqlConnection(strConnection))
10 {
11 con.Open();
12 string strSql = $"select {colums} from {tableName} where id={id}";
13
14 MySqlCommand sqlCommand = new MySqlCommand(strSql, con);
15 MySqlDataReader mySqlDataReader = sqlCommand.ExecuteReader();
16
17 if (mySqlDataReader.Read())
18 {
19 foreach (var item in type.GetProperties())
20 {
21 item.SetValue(t, mySqlDataReader[item.GetMappingName()] is DBNull ? null : mySqlDataReader[item.GetMappingName()]);
22 }
23 return t;
24 }
25 else
26 {
27 return default(T);
28 }
29 }
30 }
step3:
完成了简单查询,新增大同小异,实现代码如下

1 public bool Insert<T>(T t)
2 {
3 Type type = typeof(T);
4
5 string table = type.GetMappingName();
6 string colum = string.Join(",", type.GetProperties().Select(p => $"{p.GetMappingName()}"));
7 string value = string.Join(",", type.GetProperties().Select(p => $"'{p.GetValue(t)}'"));
8
9 using (var con = new MySqlConnection(strConnection))
10 {
11 con.Open();
12 string strSql = $"Insert into {table} ({colum}) values ({value}) ";
13
14 MySqlCommand mySqlCommand = new MySqlCommand(strSql, con);
15
16 return mySqlCommand.ExecuteNonQuery() == 1;
17 }
18
19 }
来源:https://www.cnblogs.com/wktang/p/12231886.html
