Is there any alternative to this:
Organizations.Include(\"Assets\").Where(o => o.Id == id).Single()
I would like to see something like:<
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
Good news that EF4 CTP4 currently support this feature.
See 'Say goodbye to the hardcoded ObjectQuery(T).Include calls'.
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")
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.
Another solution is to retrieve entity name using EntitySet.Name.
You code will be:
var context = new DBContext();
context.Organizations.Include(context.Assets.EntitySet.Name).Where(o => o.Id == id).Single()