栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > .Net

.NET5 ORM框架底层原理实战(1)Find<T>

.Net 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

.NET5 ORM框架底层原理实战(1)Find<T>

.NET5 ORM框架底层原理实战(1) 用到的技术? 1. .泛型 2. 反射 3. 特性 什么是ORM?

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 SqlBuilder where 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变化的时候也是执行一次
后续还会增加事务等操作

下一次再来写一个Insert
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/955669.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号