Is there any alternative to this:
Organizations.Include("Assets").Where(o => o.Id == id).Single() I would like to see something like:
Organizations.Include(o => o.Assets).Where(o => o.Id == id).Single() to avoid the hard-coded string "Assets".
In EF 4.1, there is a built-in extension method for this.
You must have a reference to "EntityFramework" assembly (where EF 4.1 lives) in your project and use System.Data.Entity.
using System.Data.Entity; If you want to include nested entities, you do it like this:
db.Customers.Include(c => c.Orders.Select(o => o.LineItems)) Not sure if this works for EF4.0 entities (ObjectContext based).
.Include("Orders.LineItems"). You can probably find others who have written extension methods that do the same thing if you really don't want to install EF4.1. Prior to 4.1, I wrote my own (borrowing from other examples), and I can tell you it's not too fun. (The expression API is ... strange.) I was glad to get access to a built-in method for this.For Entity Framework 1.0, I created some extensions methods for doing this.
public static class EntityFrameworkIncludeExtension { public static ObjectQuery<T> Include<T>(this ObjectQuery<T> src, Expression<Func<T, StructuralObject>> fetch) { return src.Include(CreateFetchingStrategyDescription(fetch)); } public static ObjectQuery<T> Include<T>(this ObjectQuery<T> src, Expression<Func<T, RelatedEnd>> fetch) { return src.Include(CreateFetchingStrategyDescription(fetch)); } public static ObjectQuery<T> Include<T, TFectchedCollection>(this ObjectQuery<T> src, Expression<Func<T, IEnumerable<TFectchedCollection>>> fetch) { return src.Include(CreateFetchingStrategyDescription(fetch)); } public static ObjectQuery<T> Include<T, FetchedChild>(this ObjectQuery<T> src, Expression<Func<T, RelatedEnd>> fetch, Expression<Func<FetchedChild, Object>> secondFetch) where FetchedChild : StructuralObject { return src.Include(CombineFetchingStrategies(fetch, secondFetch)); } public static ObjectQuery<T> Include<T, FetchedChild>(this ObjectQuery<T> src, Expression<Func<T, RelatedEnd>> fetch, Expression<Func<FetchedChild, RelatedEnd>> secondFetch) where FetchedChild : StructuralObject { return src.Include(CombineFetchingStrategies(fetch, secondFetch)); } public static ObjectQuery<T> Include<T, FetchedChild>(this ObjectQuery<T> src, Expression<Func<T, RelatedEnd>> fetch, Expression<Func<FetchedChild, StructuralObject>> secondFetch) where FetchedChild : StructuralObject { return src.Include(CombineFetchingStrategies(fetch, secondFetch)); } public static ObjectQuery<T> Include<T, FetchedChild>(this ObjectQuery<T> src, Expression<Func<T, IEnumerable<FetchedChild>>> fetch, Expression<Func<FetchedChild, Object>> secondFetch) where FetchedChild : StructuralObject { return src.Include(CombineFetchingStrategies(fetch, secondFetch)); } public static ObjectQuery<T> Include<T, FetchedChild>(this ObjectQuery<T> src, Expression<Func<T, IEnumerable<FetchedChild>>> fetch, Expression<Func<FetchedChild, RelatedEnd>> secondFetch) where FetchedChild : StructuralObject { return src.Include(CombineFetchingStrategies(fetch, secondFetch)); } public static ObjectQuery<T> Include<T, FetchedChild>(this ObjectQuery<T> src, Expression<Func<T, IEnumerable<FetchedChild>>> fetch, Expression<Func<FetchedChild, StructuralObject>> secondFetch) where FetchedChild : StructuralObject { return src.Include(CombineFetchingStrategies(fetch, secondFetch)); } private static String CreateFetchingStrategyDescription<TFetchEntity, TFetchResult>( Expression<Func<TFetchEntity, TFetchResult>> fetch) { fetch = (Expression<Func<TFetchEntity, TFetchResult>>)FixedWrappedMemberAcces.ForExpression(fetch); if (fetch.Parameters.Count > 1) throw new ArgumentException("CreateFetchingStrategyDescription support only " + "one parameter in a dynamic expression!"); int dot = fetch.Body.ToString().IndexOf(".") + 1; return fetch.Body.ToString().Remove(0, dot); } private static String CreateFetchingStrategyDescription<T>(Expression<Func<T, Object>> fetch) { return CreateFetchingStrategyDescription<T, Object>(fetch); } private static String CombineFetchingStrategies<T, TFetchedEntity>( Expression<Func<T, Object>> fetch, Expression<Func<TFetchedEntity, Object>> secondFetch) { return CombineFetchingStrategies<T, Object, TFetchedEntity, Object>(fetch, secondFetch); } private static String CombineFetchingStrategies<TFetchEntity, TFetchResult, TFetchedEntity, TSecondFetchResult>( Expression<Func<TFetchEntity, TFetchResult>> fetch, Expression<Func<TFetchedEntity, TSecondFetchResult>> secondFetch) { return CreateFetchingStrategyDescription<TFetchEntity, TFetchResult>(fetch) + "." + CreateFetchingStrategyDescription<TFetchedEntity, TSecondFetchResult>(secondFetch); } } Usage:
Orders.Include(o => o.Product); // generates .Include("Product") Orders.Include(o => o.Product.Category); // generates .Include("Product.Category") Orders.Include(o => o.History); // a 1-* reference => .Include("History") // fetch all the orders, and in the orders collection. // also include the user reference so: .Include("History.User") // but because history is an collection you cant write o => o.History.User, // there is an overload which accepts a second parameter to describe the fetching // inside the collection. Orders.Include(o => o.History, h => h.User); I haven't tested this on EF4.0, but I expect it to work.
StructuralObjectFixedWrappedMemberAcces is unknown.That's pretty easy to do, using Expressions :
public static class ObjectQueryExtensions { public static ObjectQuery<T> Include<T, TProperty>(this ObjectQuery<T> objectQuery, Expression<Func<T, TProperty>> selector) { MemberExpression memberExpr = selector.Body as MemberExpression; if (memberExpr != null) { return objectQuery.Include(memberExpr.Member.Name); } throw new ArgumentException("The expression must be a MemberExpression", "selector"); } } You can use it exactly as in the example in your question
UPDATE
Improved version, which supports multiple chained properties :
public static class ObjectQueryExtensions { public static ObjectQuery<T> Include<T, TProperty>(this ObjectQuery<T> objectQuery, Expression<Func<T, TProperty>> selector) { string propertyPath = GetPropertyPath(selector); return objectQuery.Include(propertyPath); } public static string GetPropertyPath<T, TProperty>(Expression<Func<T, TProperty>> selector) { StringBuilder sb = new StringBuilder(); MemberExpression memberExpr = selector.Body as MemberExpression; while (memberExpr != null) { string name = memberExpr.Member.Name; if (sb.Length > 0) name = name + "."; sb.Insert(0, name); if (memberExpr.Expression is ParameterExpression) return sb.ToString(); memberExpr = memberExpr.Expression as MemberExpression; } throw new ArgumentException("The expression must be a MemberExpression", "selector"); } } Example :
var query = X.Include(x => x.Foo.Bar.Baz) // equivalent to X.Include("Foo.Bar.Baz") Another option is to include an internal partial class inside your class using the TT template.
T4 code:
<# region.Begin("Member Constants"); #> public partial class <#=code.Escape(entity)#>Members { <# foreach (EdmProperty edmProperty in entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity)) { bool isForeignKey = entity.NavigationProperties.Any(np=>np.GetDependentProperties().Contains(edmProperty)); bool isDefaultValueDefinedInModel = (edmProperty.DefaultValue != null); bool generateAutomaticProperty = false; #> public const string <#=code.Escape(edmProperty)#> = "<#=code.Escape(edmProperty)#>"; <# } #> } <# region.End(); #> Which will produce something like:
#region Member Constants public partial class ContactMembers { public const string ID = "ID"; public const string OriginalSourceID = "OriginalSourceID"; public const string EnabledInd = "EnabledInd"; public const string EffectiveDTM = "EffectiveDTM"; public const string EndDTM = "EndDTM"; public const string EnterDTM = "EnterDTM"; public const string EnterUserID = "EnterUserID"; public const string LastChgDTM = "LastChgDTM"; public const string LastChgUserID = "LastChgUserID"; } #endregion