首页 - 通讯 - 封装您自己的简洁 lambda 扩展

封装您自己的简洁 lambda 扩展

2023-10-05 19:22

前言

昨天我把闲暇时打包的dapper lambda扩展开源了,并写了一篇博文《编写自己的dapper lambda扩展-使用篇》简单介绍了它的使用,今天分享一下它的设计思路

连锁编程

其实就是将多个方法通过点(.)串联起来,让代码更加简洁易读。

 new SqlConnection("").QuerySet()
                      .Where(a => www.gsm-guard.net == "aasdasd")
                      .OrderBy(a => a.CreateTime)
             .Top(10) .Select(a
=> www.gsm-guard.net).ToList();

原则是类的调用方法的返回值类型是类本身或其基类。选择返回基类的原因是为了做降级约束。比如我希望用After Top,然后Select和ToList,where或者orderBy就不能再用了。

UML图

原型代码

命令集

公共 CommandSet:IInsert、ICommand
    {
        #地区方法
        public int 插入(T 实体)
        {
            抛出NotImplementedException();
        }

        public int更新(T实体)
        {
            抛出NotImplementedException();
        }

        public int更新(表达式>更新表达式)
        {
            抛出NotImplementedException();
        }

        公共 int删除()
        {
            抛出NotImplementedException();
        }

        public IInsert IfNotExists(Expressionbool>>谓词)
        {
            抛出NotImplementedException();
        }public ICommand 其中(表达式 bool>> 谓词)
        {
            抛出NotImplementedException();
        }
        #endregion
    }

    公共 接口 ICommand
    {
        int更新(T实体);
        int更新(表达式>更新表达式);
        int删除();
    }

    公共 接口 I插入
    {
        int插入(T实体);
    }

    公共 静态  数据库
    {
        公共 静态 查询集 查询集这个 Sq l连接sqlConnection)
        {
            returnnewQuerySet();
        }

        公共 静态CommandSetCommandSet这个 SqlConnect ion sql连接)
        {
            返回命令集();
        }
    }
查看代码

 

查询集

 公共  查询集:IAggregation
    {
        #地区方法
        公共 T Get()
        {
            抛出NotImplementedException();
        }

        公共列表ToList()
        {
            抛出NotImplementedException();
        }

        公共页面列表页面列表(int页面索引,int页面大小)
        {
            抛出NotImplementedException();
        }

        公共列表UpdateSelect(表达式>@where)
        {
            抛出NotImplementedException();
        }

        public IQuery Select(表达式>选择器)
        {抛出NotImplementedException();
        }

        公共 IOption顶部(int数字)
        {
            抛出NotImplementedException();
        }

        public IOrder OrderBy(表达式> 字段)
        {
            抛出NotImplementedException();
        }

        public IOrder OrderByDescing(表达式> 字段)
        {
            抛出NotImplementedException();
        }

        公共 int 计数()
        {
            抛出NotImplementedException();
        }

        公共布尔存在()
        {
            抛出NotImplementedException();
        }

        public QuerySet 其中(表达式 bool>> 谓词)
        {抛出NotImplementedException();
        }
        #endregion
    }

    公共 接口 IAggregation : IOrder
    {
        int计数();
        布尔存在();
    }

    公共 接口 IOrder : IOption
    {
        IOrder OrderBy(表达式> 字段);
        IOrder OrderByDescing(表达式> 字段);
    }

    公共 接口 IOption : IQuery, IUpdateSelect
    {
        IQuery Select(表达式>选择器);

        IOption顶部(intnum);
    }

    公共 接口 IUpdateSelect
    {
        列表 UpdateSelect(表达式> where);
    }

    公共 接口 IQuery
    {
        获取();

        列表 ToList();PageList PageList(int pageIndex, int pageSize);
    }
查看代码

以上是基本设计模型。如果对具体实现有疑问,可以查看我的源码。

表达式树解析

具体实现会涉及到很多表达式树的解析,比如where条件、部分字段更新等。我实现的时候有两个步骤:先修复树,然后翻译。然而,无论采取哪一步,都必须遍历表达式树。

表达式树

百度的定义:又称“表达式目录树”,以数据的形式表示语言级别的代码。它是一个抽象语法树或数据结构。

我对它的理解是,它本质上是一棵二叉树,节点有自己的nodetype等属性。

并且其遍历方式为前序遍历

预购穿越

百度的定义:日历首先访问根节点,然后遍历左子树,最后遍历右子树。遍历左右子树时,仍然先访问根节点,然后遍历左子树,最后遍历右子树。下图为示例

遍历结果为:ABDECF

举个实际例子:

从上图可以看出,我们会先遍历到根节点的NodeType AndAlso,翻译为and,然后到节点2,NodeType的Equal翻译为=,然后到节点3,它被翻译为Name,然后到节点4,它被翻译为'skychen',那么节点3和4的拼接将是Name = 'skychen'。如果类比节点6和7是Age >= 18,那么最终的拼接语句就是Name = 'skychen' and Age >= 18。

秀树

为了树修复的目的,为了我们更好的翻译,例如www.gsm-guard.net表达式树中的NodeType是MemberAccess。我希望将NodeType转换为Constant类型,以 '2018-06-27 16:18:00' 这个值作为翻译。

以上是设计和实现的要点。具体实现问题可以查看源码。如果您有建议和疑问,可以在下方留言。如果对你有用,希望你能点击推荐作为对我的支持。

再次双手提供源码:https://www.gsm-guard.net/SkyChenSky/Sikiro.DapperLambdaExtension.MsSql