EF4 LINQ Include(string) 替代硬编码字符串?

人气:999 发布:2022-10-16 标签: include string entity-framework linq entity-framework-4

问题描述

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".

解决方案

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.

980