Entity Framework - Include使用Lambda表示式

Entity Framework - Include使用Lambda表示式

在EF中Eager loading是透過Include來載入關連屬性,但Include方法只提供字串做為參數,非強行別模式,若未來維護時修改了欄位名稱就可能會忘記修改到.透過以下的Extend method就可以讓Include使用lambda表示式來做強型別的指定

   public static class ObjectQueryExtensions
    {
        public static ObjectQuery<T> Include<T>(this ObjectQuery<T> query, Expression<Func<T, object>> selector)
        {
            string path = new PropertyPathVisitor().GetPropertyPath(selector);
            return query.Include(path);
        }
 
        class PropertyPathVisitor : ExpressionVisitor
        {
            private Stack<string> _stack;
            public string GetPropertyPath(Expression expression)
            {
                _stack = new Stack<string>();
                Visit(expression);
                return _stack
                    .Aggregate(
                       new StringBuilder(),
                       (sb, name) =>
                           (sb.Length > 0 ? sb.Append(".") : sb).Append(name))
                   .ToString();
            }
 
            protected override Expression VisitMember(MemberExpression expression)
            {
                if (_stack != null)
                    _stack.Push(expression.Member.Name);
                return base.VisitMember(expression);
            }
 
            protected override Expression VisitMethodCall(MethodCallExpression expression)
            {
                if (IsLinqOperator(expression.Method))
                {
                    for (int i = 1; i < expression.Arguments.Count; i++)
                    {
                        Visit(expression.Arguments[i]);
                    }
                    Visit(expression.Arguments[0]);
                    return expression;
                }
                return base.VisitMethodCall(expression);
            }
 
            private static bool IsLinqOperator(MethodInfo method)
            {
                if (method.DeclaringType != typeof(Queryable) && method.DeclaringType != typeof(Enumerable))
                    return false;
                return Attribute.GetCustomAttribute(method, typeof(ExtensionAttribute)) != null;
            }
        }
    }

使用方式

單一屬性

var query = from ord in db.Orders.Include(o => o.OrderDetails) where ord.Date >= DateTime.Today select ord;


階層屬性

var query = from ord in db.Orders.Include(o => OrderDetails.Select(od => od.Discounts.Select(d => d.Campaign)))

 

多階層時對List屬性選擇方式

var query = from ord in db.Orders.Include(o => o.OrderDetails.SelectMany(od => od.Discounts).Select(d => d.Campaign))