在Entity Framework中如果不設定為Lazy Loading Enable=true,勢必要自己處理關聯資料的載入,如:用Load或Include的,但因為Include的參數是用string,個人很討厭沒有IntelliSense,且String不小必改了TableName後,工具不易找到錯誤,所以小弟我寫一個Extension Method來擴展。
在Entity Framework中如果不設定為Lazy Loading Enable=true,勢必要自己處理關聯資料的載入,如:用Load或Include的,但因為Include的參數是用string,個人很討厭沒有IntelliSense,且用String改了TableName後,工具不易找到錯誤,所以小弟我寫一個Extension Method來擴展。
//原弱型別的寫法
AdventureWorksLT2008R2Entities context = new AdventureWorksLT2008R2Entities();
var customer = context.Customer.Include("SalesOrderHeader").ToList();
//擴展的強型別寫法
AdventureWorksLT2008R2Entities context = new AdventureWorksLT2008R2Entities();
var customer = context.Customer.Include(x => x.SalesOrderHeader).ToList();
NOTE:
這個方法暫時不適用Collection後又在關聯,如上一個例子SalesOrderHeader是Collection,無法這樣下x.SalesOrderHeader.SalesOrderDetail,為什麼是暫時,因為小弟還沒想出好的寫法,用x.SalesOrderHeader[0].SalesOrderDetail或x.SalesOrderHeader.First().SalesOrderDetail嗎,感覺挺醜的。
Source Code
public static IQueryable<T> Include<T>(this ObjectSet<T> source, Expression<Func<T, object>> path) where T : class
{
//偷吃步的作法,如:Expression為x=>x.Customer.CustomerAddress,ToString後直接從第一個.分割,取後面的Customer.CustomerAddress
string spath = path.Body.ToString();
spath = spath.Substring(spath.IndexOf('.') + 1);
return source.Include(spath);
}
上面的Code比較偷懶,應該要分析一下Expression比較正統
public static IQueryable<T> Include<T>(this ObjectSet<T> source, Expression<Func<T, object>> path) where T : class
{
StringBuilder pathBuilder = new StringBuilder();
MemberExpression pro = path.Body as MemberExpression;
while (pro != null)
{
//Exprssion有點像鏈結串列,從Statemant的後方往前連結,如: x=> x.Customer.CustomerAddress
//path.Body是CustomerAddress
//CustomerAddress的Expression是Customer
//Customer的Expression是x
pathBuilder.Insert(0, "." + pro.Member.Name);
pro = pro.Expression as MemberExpression;
}
return source.Include(pathBuilder.ToString(1, pathBuilder.Length-1));
}
NOTE:
我沒有做錯誤檢查,想說有錯Entity Framework也會丟Exception,自己就不多事了。
圖1 Model關聯圖