zoukankan      html  css  js  c++  java
  • 抛弃EF,20分构建一个属于自己的ORM框架

    Poiuyt_cyc

    博客园首页新随笔联系订阅管理随笔 - 11  文章 - 0  评论 - 111

    抛弃EF,20分构建一个属于自己的ORM框架

    相信EF大家都不陌生了,因为数据库表跟程序实体是一一对应的原因,我们能够通过lambda这种函数式的编程方式进行操作数据库,感觉非常清晰明了。与我们直接写SQL相比,lambda是强类型,拥有更好的扩展性,伸缩性,而且编程更加的方便,快捷。。下面我们就基于Expression和lambda来与大家构建一个属于自己的ORM框架。

    思路的话很简单,就是将lambda转换成我们对应的数据库所需的查询条件,然后执行查询,再将结果以反射的方式封装成List<T>返回出去。

    Expression

    大家使用EF的时候多多少少会留意到有Expression这个东西。特别是查询时会看到要你传入Expression<Func<T,bool>>这样类型的参数,它又和Func<T,bool>有什么比同呢?

    Expression<Func<T,bool>>是表达式树,我们可以通过它来分析我们的委托中的函数。当调用Compile方法后就会变成委托,才能执行。

    Func<T,bool>只是一个普通的委托。

    例如我们现在有个实体类Staff

     public class Staff

        {

            public string Name { get; set; }

            public int Age { get; set; }

            public string Code { get; set; }

            public DateTime? Birthday { get; set; }

            public bool Deletion { get; set; }

        }

    我们还有一个这样的方法

      class Program

        {

            static void Main(string[] args)

            {

                FindAs<Staff>(x => x.Code == "张三" && x.Name.Contains("张"));

            }

            public static List<T> FindAs<T>(Expression<Func<T, bool>> func)

            {

                //将func转换成对应数据库的查询条件,然后执行查询

                return null;//将结果返回

            }

        }

    我们希望通过 FindAs<Staff>(x => x.Age <50 && x.Name.Contains("张")); 就能查询出Staff表中Age<50并且Name包含有“张”字的人的信息。而生成的sql语句应该是select * from staff where Age<50 and Name like '%张%'。现在我们就来分析下这个func

    从上面的图我们可以看到当前的Expression是一个lambda表达式,我们点开它的body看看。

    我们可以看到body里分为左边和右边,还有NodeType。和我们的lambda对比下看看'x => x.Code =="张三" && x.Name.Contains("张")'是不是找到点灵感了?我们再继续把左边和右边拆开看看。

    可以看到我们需要的信息都有了,看来转换成SQL已经不是什么难事了,动手开搞了。

     class Program

        {

            static void Main(string[] args)

            {

                FindAs<Staff>(x => x.Code == "张三" && x.Name.Contains("张"));

                FindAs<Staff>(x => x.Age <= 12 && x.Name.Contains("张"));

                Console.ReadKey();

            }

            public static List<T> FindAs<T>(Expression<Func<T, bool>> func)

            {

                BinaryExpression Binary = func.Body as BinaryExpression;

                string left = ResovleFunc(Binary.Left);

                string right = ResovleLinqToObject(Binary.Right);

                string oper = GetOperator(Binary.NodeType);

                string sql = string.Format("select * from {0} where {1}", typeof(T).Name, left + oper + right);

                Console.WriteLine(sql);

                return null;//将结果返回

            }

            //解析一般的条件,例如x=>x.name==xxxx   x.age==xxx

            public static string ResovleFunc(Expression express)

            {

                var inner = express as BinaryExpression;

                string Name = (inner.Left as MemberExpression).Member.Name;

                object Value = (inner.Right as ConstantExpression).Value;

                var Operator = GetOperator(inner.NodeType);

                string Result = string.Format("({0} {1} '{2}')", Name, Operator, Value);

                return Result;

            }

            //解析linq to object这类扩展方法

            public static string ResovleLinqToObject(Expression expression)

            {

                var MethodCall = expression as MethodCallExpression;

                var MethodName = MethodCall.Method.Name;

                if (MethodName == "Contains")

                {

                    object Temp_Vale = (MethodCall.Arguments[0] as ConstantExpression).Value;

                    string Value = string.Format("%{0}%", Temp_Vale);

                    string Name = (MethodCall.Object as MemberExpression).Member.Name;

                    string Result = string.Format("{0} like '{1}'", Name, Value);

                    return Result;

                }

                return null;

            }

            public static string GetOperator(ExpressionType expressiontype)

            {

                switch (expressiontype)

                {

                    case ExpressionType.And:

                        return "and";

                    case ExpressionType.AndAlso:

                        return "and";

                    case ExpressionType.Or:

                        return "or";

                    case ExpressionType.OrElse:

                        return "or";

                    case ExpressionType.Equal:

                        return "=";

        

  • 相关阅读:
    router基本使用
    函数声明 和 var声明的优先级
    适用于Windows桌面应用程序的.NET Core 3
    在.Net Core 3.0中尝试新的System.Text.Json API
    在WPF中使用.NET Core 3.0依赖项注入和服务提供程序
    WPF控件获得焦点时去除虚线框
    Call asynchronous method in constructor
    将自定义控件加载到RichTextbox并进行交互
    WPF应用无法使用Snoop分析的解决办法
    关于序列化和反序列化
  • 原文地址:https://www.cnblogs.com/zhangxiaolei521/p/5551641.html
Copyright © 2011-2022 走看看