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

对象表达式用于解析 Expression<Func<Student, object>> expr = s => new { s.Id, s.Name } 这种形式的目录树,使用场景:UpdateInclude(Student entity, Expression<Func<Student, object>> expr) 更新实体中指定的列。

Select表达式类似上面对象表达式的解析,不同的是Select表达式可能包含导航属性,而对象表达式则会忽略导航属性

一、对象表达式解析

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; }
    }
}

猜你喜欢

转载自www.cnblogs.com/diwu0510/p/10663442.html
今日推荐