尝试手写orm框架

前言:

在使用各种的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

时间: 2024-08-05 23:37:15

尝试手写orm框架的相关文章

(二)springMvc原理和手写springMvc框架

我们从两个方面了解springmvc执行原理,首先我们去熟悉springmvc执行的过程,然后知道原理后通过手写springmvc去深入了解代码中执行过程. (一)SpringMVC流程图 (二)SpringMVC流程 1.  用户发送请求至前端控制器DispatcherServlet. 2.  DispatcherServlet收到请求调用HandlerMapping处理器映射器. 3.  处理器映射器找到具体的处理器(可以根据xml配置.注解进行查找),生成处理器对象及处理器拦截器(如果有则

手写SpringMVC 框架

手写SpringMVC框架 细嗅蔷薇 心有猛虎 背景:Spring 想必大家都听说过,可能现在更多流行的是Spring Boot 和Spring Cloud 框架:但是SpringMVC 作为一款实现了MVC 设计模式的web (表现层) 层框架,其高开发效率和高性能也是现在很多公司仍在采用的框架:除此之外,Spring 源码大师级的代码规范和设计思想都十分值得学习:退一步说,Spring Boot 框架底层也有很多Spring 的东西,而且面试的时候还会经常被问到SpringMVC 原理,一般

手写Spring框架,加深对Spring工作机制的理解!

在我们的日常工作中,经常会用到Spring.Spring Boot.Spring Cloud.Struts.Mybatis.Hibernate等开源框架,有了这些框架的诞生,平时的开发工作量也是变得越来越轻松,我们用 Spring Boot 分分钟可以新建一个Web项目. 记得自己刚开始工作的时候还是在用Servlet写Web项目,自己写数据库连接池,用原生JDBC操作数据库,好了不发散了.回到这篇文章的主题,今天通过手写Spring框架,帮大家深入了解一下Spring的工作机制,文中涉及的代码

手写集合框架LinkedList实现篇

<手写集合框架>LinkedList篇 嘿嘿嘿,拖延症犯了,这几天不怎么想写代码,所以趁没事干就写写了.进入正文 还是老套路嘻嘻嘻,因为我之前写了那个准备篇,对node已经描述的从差不多了,所以我就不过多描述了. 直接贴完代码强行解释一波 一.定义接口 public interface newList<T> { //定义泛型,因为Object可以存储任意类型,有时候我们需要 //用泛型 代替Object public void add(Object object); //集合的添加

手写springIoc框架

springIoc的底层实现原理 1.读取bean的XML配置文件 2.使用beanId查找bean配置,并获取配置文件中class地址. 3.使用Java反射技术实例化对象 4.获取属性配置,使用反射技术进行赋值 使用人家spring框架读取对象 创建实体 package com.itmayiedu.service; public class UserEntity { private String userId; private String userName; public UserEnti

自己写ORM框架 DBUtils

ORM框架想必大家都比较熟知了,即对象关系映射(英语:Object Relation Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换.从效果上说,它其实是创建了一个可在编程语言里使用的"虚拟对象数据库". 当你开发一个应用程序的时候(不使用O/R MAPPING),你可能会写不少数据访问层的代码,用来从数据库保存,删除,读取对象信息,等等. 现在流行的ORM框架有: JAVA系列:APACHE

自己写ORM框架 DBUtils_DG Java(C#的写在链接里)

ORM框架想必大家都比较熟知了,即对象关系映射(英语:Object Relation Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换.从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”. 当你开发一个应用程序的时候(不使用O/R MAPPING),你可能会写不少数据访问层的代码,用来从数据库保存,删除,读取对象信息,等等. 现在流行的ORM框架有: JAVA系列:APACHE OJB,C

纯手写SpringBoot框架之注解方式启动SpringMVC容器

使用Java语言创建Tomcat容器,并且通过Tomcat执行Servlet,接下来,将会使用Java语言在SpringBoot创建内置Tomcat,使用注解方式启动SpringMVC容器. 代码实现.1.pom.xml文件,需要依赖的jar包. <dependencies> <!--Java语言操作Tomcat--> <dependency> <groupId>org.apache.tomcat.embed</groupId> <arti

手写ORM持久层框架

根据尚学堂录的教程做的.: 配置文件 db.properties driver=com.mysql.jdbc.Driver url=jdbc\:mysql\://127.0.0.1\:3306/sorm user=root password=123 usingDB=mysql srcPath=/home/frank/MyEclipseWorkSpace/S_ORM/src poPackage=com.frank.po queryClass=com.frank.sorm.core.imp.MySq