【手擼一個ORM】第六步、對象表達式解析和Select表達式解析
阿新 • • 發佈:2019-04-07
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表達式解析