前言:
在使用各种的 ORM 框架的过程中, 菜鸟的我始终没有搞懂底层实现技术, 最近刚好没事找了些视频和资料了解一点皮毛, 想记录下, 大家勿喷.
所谓的 ORM(Object Relational Mapping) 对象关系映射 官方解释是通过使用描述对象和数据库之间映射的元数据, 将面向对象程序的对象自动持久化到关系数据库中.
个人理解就是一个数据库访问的帮助类, 可以让我们不用手写 sql, 就完成数据库的访问
使用的技术: 泛型, 反射, 特性, 扩展
摸索步骤:
step1
新建项目, 建几个类库, 大家熟悉的三层.
step2:
在数据访问层新建一个 sqlhelper 类;
2.1 添加一个数据查询的方法, 还需要添加 model 层添加 SysUser, 完成实体与表映射, 实现代码 如下
- public class SysUser
- {
- public long Id { get; set; }
- public string Login_Name { get; set; }
- public string Name { get; set; }
- public string Icon { get; set; }
- public string Password { get; set; }
- public string Salt { get; set; }
- public string Tel { get; set; }
- public string Email { get; set; }
- public SByte Locked { get; set; }
- public DateTime Create_Date { get; set; }
- public long Create_By { get; set; }
- public DateTime Update_Date { get; set; }
- public long Update_By { get; set; }
- public string Remarks { get; set; }
- public SByte Del_Flag { get; set; }
- }
- View Code
- public SysUser QueryUser(string id)
- {
- Type type = typeof(SysUser);
- SysUser sysUser = new SysUser();
- using (var con = new MySqlConnection(strConnection))
- {
- con.Open();
- 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}";
- MySqlCommand sqlCommand = new MySqlCommand(strSql, con);
- MySqlDataReader mySqlDataReader = sqlCommand.ExecuteReader();
- if(mySqlDataReader.Read())
- {
- if (mySqlDataReader.Read())
- {
- foreach (var item in type.GetProperties())
- {
- item.SetValue(sysUser, mySqlDataReader[item.Name] is DBNull ? null : mySqlDataReader[item.Name]);
- }
- }
- }
- }
- return sysUser;
- }
- View Code
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. 可空值类型处理
实现代码
- public T QueryById<T>(string id)
- {
- Type type = typeof(T);
- T t = Activator.CreateInstance<T>();// 创建实体
- string tableName = type.Name;
- string colums = string.Join(",", type.GetProperties().Select(p => $"{p.Name}"));// 拼接查询字段
- using (var con = new MySqlConnection(strConnection))
- {
- con.Open();
- string strSql = $"select {colums} from {tableName} where id={id}";
- MySqlCommand sqlCommand = new MySqlCommand(strSql, con);
- MySqlDataReader mySqlDataReader = sqlCommand.ExecuteReader();
- if (mySqlDataReader.Read())
- {
- foreach (var item in type.GetProperties())
- {
- item.SetValue(t, mySqlDataReader[item.Name] is DBNull ? null : mySqlDataReader[item.Name]);// 需要添加 Null 判断
- }
- return t;
- }
- else
- {
- return default(T);
- }
- }
- }
- View Code
存在问题: 实体类名与数据库表名不一致, 实体属性名与数据表字段名不一致
解决上面两个问题 可以使用特性 (解释: 特性本质就是一个类, 间接或直接继承 Attribute 就是一个特性, 其为目标元素提供关联的附加信息, 并在运行时以反射的方式来获取附加信息)
相关代码如下
抽象类
- public abstract class AbstractMappingAttribute: Attribute
- {
- private string _mappingName;
- public AbstractMappingAttribute(string mappingName)
- {
- this._mappingName = mappingName;
- }
- public string GetMappingName()
- {
- return this._mappingName;
- }
- }
- View Code
实体类名与表名不一致时
- [AttributeUsage(AttributeTargets.Class)]
- public class MappingTableAttribute : AbstractMappingAttribute
- {
- public MappingTableAttribute(string tableName) : base(tableName)
- {
- }
- }
- View Code
实体属性与表字段不一致时
- [AttributeUsage(AttributeTargets.Property)]
- public class MappingColumAttribute : AbstractMappingAttribute
- {
- public MappingColumAttribute(string colName) : base(colName)
- {
- }
- }
- View Code
注意: 在使用特性须加上本特性类作用的范围, 简单理解就是用在类上面还是类的属性或行为上.
实体类使用自定义特性代码如下
- [MappingTableAttribute("sys_user")]
- public class SysUser
- {
- public long Id { get; set; }
- public string Login_Name { get; set; }
- [MappingColumAttribute("nick_name")]
- public string Name { get; set; }
- public string Icon { get; set; }
- public string Password { get; set; }
- public string Salt { get; set; }
- public string Tel { get; set; }
- public string Email { get; set; }
- public SByte Locked { get; set; }
- public DateTime Create_Date { get; set; }
- public long Create_By { get; set; }
- public DateTime Update_Date { get; set; }
- public long Update_By { get; set; }
- public string Remarks { get; set; }
- public SByte Del_Flag { get; set; }
- }
- View Code
怎么获取实体的自定义特性描述的信息?
这里面需要用到扩展方法
- public static class MappingAttributeExtend
- {
- public static string GetMappingName<T>(this T t) where T : MemberInfo
- {
- if (t.IsDefined(typeof(AbstractMappingAttribute), true))
- {
- AbstractMappingAttribute abstractMappingAttribute = t.GetCustomAttribute<AbstractMappingAttribute>();
- return abstractMappingAttribute.GetMappingName();
- }
- else
- {
- return t.Name;
- }
- }
- }
- View Code
2.3 经过 2.2 一步步优化最终通用查询方法代码如下
- public T QueryById<T>(string id)
- {
- Type type = typeof(T);
- T t = Activator.CreateInstance<T>();// 创建实体
- string tableName = type.GetMappingName();
- string colums = string.Join(",", type.GetProperties().Select(p => $"{p.GetMappingName()}"));// 拼接查询字段
- using (var con = new MySqlConnection(strConnection))
- {
- con.Open();
- string strSql = $"select {colums} from {tableName} where id={id}";
- MySqlCommand sqlCommand = new MySqlCommand(strSql, con);
- MySqlDataReader mySqlDataReader = sqlCommand.ExecuteReader();
- if (mySqlDataReader.Read())
- {
- foreach (var item in type.GetProperties())
- {
- item.SetValue(t, mySqlDataReader[item.GetMappingName()] is DBNull ? null : mySqlDataReader[item.GetMappingName()]);
- }
- return t;
- }
- else
- {
- return default(T);
- }
- }
- }
- View Code
- step3:
完成了简单查询, 新增大同小异, 实现代码如下
- public bool Insert<T>(T t)
- {
- Type type = typeof(T);
- string table = type.GetMappingName();
- string colum = string.Join(",", type.GetProperties().Select(p => $"{p.GetMappingName()}"));
- string value = string.Join(",", type.GetProperties().Select(p => $"'{p.GetValue(t)}'"));
- using (var con = new MySqlConnection(strConnection))
- {
- con.Open();
- string strSql = $"Insert into {table} ({colum}) values ({value})";
- MySqlCommand mySqlCommand = new MySqlCommand(strSql, con);
- return mySqlCommand.ExecuteNonQuery() == 1;
- }
- }
- View Code
来源: http://www.bubuko.com/infodetail-3393772.html