在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關聯圖