• 【手撸一个ORM】第六步、对象表达式解析和Select表达式解析


    说明

    一个Orm自然不仅仅包含条件表达式,还会有如下的场景:

    OrderBy(s => s.StudentName) 
    Select<StudentDto>(s => new StudentDto { s.Id, s.Name, SchoolName = s.School.Name})

    而应用场景的不同,导致解析的方式也有所不同,在这里我们又定义了两个解析类:[ObjectMemberVisitor] 和 [SelectExpressionResolver]

    [ObjectMemberVisitor] 主要用于从表达式中解析出参数的属性名,会自动忽略导航属性

    [SelectExpressionResolver] 主要用于查询的Select方法,也是用于从表达式中解析出属性名,与ObjectMemberVisitor不同的是它不会忽略导航属性。

    从下面的代码可以看出,两个类虽然功能类似,但是代码差异很大,主要是因为ObjectMemberVisitor的使用场景比较简单,只需要拿到表达式的Member(成员)就可以了,不必考虑太多。但SelectExpressionResolver不同,其解析结果需要反馈给查询工具更多信息,包括Member与Parameter的映射关系等。


     对象表达式解析

    using System.Collections.Generic;
    using System.Linq.Expressions;
    
    namespace MyOrm.Expressions
    {
        public class ObjectMemberVisitor : ExpressionVisitor
        {
            private readonly List<string> _propertyList;
    
            public ObjectMemberVisitor()
            {
                _propertyList = new List<string>();
            }
    
            public List<string> GetPropertyList()
            {
                return _propertyList;
            }
    
            public void Clear()
            {
                _propertyList.Clear();
            }
    
            protected override Expression VisitMember(MemberExpression node)
            {
                if (node.Expression != null && node.Expression.NodeType == ExpressionType.Parameter)
                {
                    _propertyList.Add(node.Member.Name);
                }
                return node;
            }
    
            protected override Expression VisitNew(NewExpression node)
            {
                foreach (var arg in node.Arguments)
                {
                    if (arg.NodeType == ExpressionType.MemberAccess)
                    {
                        var member = (MemberExpression) arg;
                        if (member.Expression != null && member.Expression.NodeType == ExpressionType.Parameter)
                        {
                            _propertyList.Add(member.Member.Name);
                        }
                    }
                }
                return node;
            }
        }
    }

    Select表达式解析

    using System;
    using System.Collections.Generic;
    using System.Linq.Expressions;
    using System.Text;
    using MyOrm.Reflections;
    
    namespace MyOrm.Expressions
    {
        public class SelectExpressionResolver
        {
            private readonly List<string> _propertyList;
    
            private readonly List<SelectResolveResult> _dict;
    
            private Type _targetType;
    
            public SelectExpressionResolver()
            {
                _propertyList = new List<string>();
                _dict = new List<SelectResolveResult>();
            }
    
            public List<SelectResolveResult> GetPropertyList()
            {
                return _dict;
            }
    
            public Type GetTargetType()
            {
                return _targetType;
            }
    
            public void Clear()
            {
                _propertyList.Clear();
            }
    
            public void Visit(LambdaExpression expression)
            {
                if (expression.Body.NodeType == ExpressionType.MemberAccess)
                {
                    VisitMember((MemberExpression)expression.Body);
                }
                else if (expression.Body.NodeType == ExpressionType.MemberInit)
                {
                    VisitMemberInit((MemberInitExpression)expression.Body);
                }
                else if(expression.Body.NodeType == ExpressionType.New)
                {
                    VisitNew((NewExpression)expression.Body);
                }
            }
    
            protected Expression VisitMember(MemberExpression node)
            {
                var rootType = node.GetRootType(out var stack);
                if (rootType == ExpressionType.Parameter)
                {
                    if (stack.Count == 1)
                    {
                        var propertyName = stack.Pop();
                        var memberName = node.Member.Name;
    
                        _dict.Add(new SelectResolveResult
                        {
                            PropertyName = propertyName,
                            MemberName = memberName,
                            FieldName = ""
                        });
                    }
                    else if (stack.Count == 2)
                    {
                        var propertyName = stack.Pop();
                        var fieldName = stack.Pop();
                        var memberName = node.Member.Name;
                        _dict.Add(new SelectResolveResult
                        {
                            MemberName = memberName,
                            PropertyName = propertyName,
                            FieldName = fieldName
                        });
                    }
                }
                return node;
            }
    
            protected Expression VisitNew(NewExpression node)
            {
                _targetType = node.Type;
                Console.WriteLine(_targetType);
                if (node.Members != null)
                {
                    for (var i = 0; i < node.Members.Count; i++)
                    {
                        if (node.Arguments[i].NodeType == ExpressionType.MemberAccess)
                        {
                            var member = (MemberExpression) node.Arguments[i];
                            var rootType = member.GetRootType(out var stack);
                            if (rootType == ExpressionType.Parameter)
                            {
                                if (stack.Count == 1)
                                {
                                    var propertyName = stack.Pop();
                                    var memberName = node.Members[i].Name;
    
                                    _dict.Add(new SelectResolveResult
                                    {
                                        PropertyName = propertyName,
                                        MemberName = memberName,
                                        FieldName = ""
                                    });
                                }
                                else if (stack.Count == 2)
                                {
                                    var propertyName = stack.Pop();
                                    var fieldName = stack.Pop();
                                    var memberName = node.Members[i].Name;
                                    _dict.Add(new SelectResolveResult
                                    {
                                        PropertyName = propertyName,
                                        MemberName = memberName,
                                        FieldName = fieldName
                                    });
                                }
                            }
                        }
                    }
                }
    
                return node;
            }
    
            protected void VisitMemberInit(MemberInitExpression node)
            {
                foreach (var binding in node.Bindings)
                {
                    var result = new SelectResolveResult { MemberName = binding.Member.Name };
                    if (binding.BindingType == MemberBindingType.Assignment)
                    {
                        var expression = ((MemberAssignment) binding).Expression;
                        if (expression.NodeType == ExpressionType.MemberAccess)
                        {
                            var member = (MemberExpression)expression;
                            var rootType = member.GetRootType(out var stack);
                            if (rootType == ExpressionType.Parameter)
                            {
                                if (stack.Count == 1)
                                {
                                    var propertyName = stack.Pop();
                                    var memberName = binding.Member.Name;
    
                                    _dict.Add(new SelectResolveResult
                                    {
                                        PropertyName = propertyName,
                                        MemberName = memberName,
                                        FieldName = ""
                                    });
                                }
                                else if (stack.Count == 2)
                                {
                                    var propertyName = stack.Pop();
                                    var fieldName = stack.Pop();
                                    var memberName = binding.Member.Name;
                                    _dict.Add(new SelectResolveResult
                                    {
                                        PropertyName = propertyName,
                                        MemberName = memberName,
                                        FieldName = fieldName
                                    });
                                }
                            }
                        }
                    }
                }
            }
    
            private string ResolveStackToField(Stack<string> parameterStack)
            {
                switch (parameterStack.Count)
                {
                    case 2:
                    {
                        // 调用了导航属性
                        var propertyName = parameterStack.Pop();
                        var propertyFieldName = parameterStack.Pop();
                            
                        return $"{propertyName}.{propertyFieldName}";
                    }
                    case 1:
                    {
                        var propertyName = parameterStack.Pop();
                        return propertyName;
                    }
                    default:
                        throw new ArgumentException("尚未支持大于2层属性调用。如 student.Clazz.School.Id>10,请使用类似 student.Clazz.SchoolId > 0 替代");
                }
            }
        }
    
        public class SelectResolveResult
        {
            public string MemberName { get; set; }
    
            public string PropertyName { get; set; }
    
            public string FieldName { get; set; }
        }
    }
  • 相关阅读:
    forms组件、cookie与session
    choices参数、MTV与MVC模型、Ajax、序列化组件、sweetalert搭建页面、自定义分页器
    Django 常用字段,数据库查询优化 only与defer
    django配置代码
    django 模板层、模型层
    Django 请求生命周期、路由层
    centos6.8安装httpd后无法访问
    初次认识dedecms和帝国cms内容管理系统
    遇到一个json解码失败的问题
    关于apache配置映射端口
  • 原文地址:https://www.cnblogs.com/diwu0510/p/10663442.html
Copyright © 2020-2023  润新知