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 =
OrderDetails.Select(od => od.Discounts.Select(d => d.Campaign)))from ord
in
db.Orders.Include(o =>
多階層時對List屬性選擇方式
var query =
from ord
in
db.Orders.Include(o => o.OrderDetails
.SelectMany(od => od.Discounts)
.Select(d => d.Campaign))