1. 程式人生 > >【手擼一個ORM】第六步、對象表達式解析和Select表達式解析

【手擼一個ORM】第六步、對象表達式解析和Select表達式解析

member ++ access over def 大於 () 表達式 cti

對象表達式用於解析 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; }
    }
}

【手擼一個ORM】第六步、對象表達式解析和Select表達式解析