EF4 LINQ Include(string) alternative to hard-coded string?

前端 未结 7 2260
借酒劲吻你
借酒劲吻你 2020-12-29 11:13

Is there any alternative to this:

Organizations.Include(\"Assets\").Where(o => o.Id == id).Single()

I would like to see something like:<

相关标签:
7条回答
  • 2020-12-29 11:21

    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
    
    0 讨论(0)
  • 2020-12-29 11:22

    Good news that EF4 CTP4 currently support this feature.

    0 讨论(0)
  • 2020-12-29 11:36

    See 'Say goodbye to the hardcoded ObjectQuery(T).Include calls'.

    0 讨论(0)
  • 2020-12-29 11:38

    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")
    
    0 讨论(0)
  • 2020-12-29 11:41

    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.

    0 讨论(0)
  • 2020-12-29 11:45

    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()
    
    0 讨论(0)
提交回复
热议问题