Entity Framework Include with Func next

I defined an Include with Func.

Cool. But what about Include("Products.Order_Details")?

Indeed my Include can only take one relationship level.

So I change my code like this:

public static class ObjectQueryExtension

{

    public static ObjectQuery<T> Include<T>(this ObjectQuery<T> mainQuery, Expression<Func<T, object>> subSelector)

    {

        return mainQuery.Include(FuncToString(subSelector.Body));

    }

    private static string FuncToString(Expression selector)

    {

        switch (selector.NodeType)

        {

            case ExpressionType.MemberAccess:

                return ((selector as MemberExpression).Member as Reflection.PropertyInfo).Name;

            case ExpressionType.Call:

                var method = selector as MethodCallExpression;

                return FuncToString(method.Arguments[0]) + "." + FuncToString(method.Arguments[1]);

            case ExpressionType.Quote:

                return FuncToString(((selector as UnaryExpression).Operand as LambdaExpression).Body);

        }

        throw new InvalidOperationException();

    }

    public static K Include<T, K>(this EntityCollection<T> mainQuery, Expression<Func<T, object>> subSelector)

        where T : EntityObject, IEntityWithRelationships

        where K : class

    {

        return null;

    }

    public static K Include<T, K>(this T mainQuery, Expression<Func<T, object>> subSelector)

        where T : EntityObject

        where K : class

    {

        return null;

    }

}

and I can now do this:

context.Categories.Include(ca => ca.Products.Include<Products, Order_Details>(p => p.Order_Details).Include<Order_Details, Orders>(od => od.Orders))

Isn't it cool?

Published Fri, Jun 6 2008 16:49 by Matthieu MEZIL

Comments

# re: Entity Framework Include with Func next

Absolutely incredible! I don't know what else to say

Tuesday, August 26, 2008 2:04 PM by Mike L

# re: Entity Framework Include with Func next

Thanks Big Smile

Tuesday, August 26, 2008 2:09 PM by Matthieu MEZIL

# Entity Framework Include with Func

Tuesday, April 21, 2009 4:49 PM by Jiří {x2} Činčura

# re: Entity Framework Include with Func next

Very cool!  I also hate using strings in this context: it seems counterintuitive, and very susceptible to mistakes.  At the same time, I'm not sure I'll be using this method.  Which of the following is easier for the next guy looking at my code to understand?

           Room room = ctx.Room

               .Include("Sessions.User")

               .Include("Sessions.Whiteboards.Owner")

               .Include("Sessions.Whiteboards.WhiteboardShape")

               .Include("Sessions.MediaStreams")

               .Include("Owner")

               .FirstOrDefault(r => r.OwnerID == ownerUserID && r.Name == roomName);

           Room room2 = ctx.Room

               .Include(r => r.Sessions.Include<Session, User>(s => s.User))

               .Include(r => r.Sessions.Include<Session, Whiteboard>(s => s.Whiteboards).Include<Whiteboard, User>(w => w.Owner))

               .Include(r => r.Sessions.Include<Session, Whiteboard>(s => s.Whiteboards).Include<Whiteboard, WhiteboardShape>(w => w.WhiteboardShape))

               .Include(r => r.Sessions.Include<Session, MediaStream>(s => s.MediaStreams))

               .Include(r => r.Owner)

               .FirstOrDefault(r => r.OwnerID == ownerUserID && r.Name == roomName);

They both do the same thing, but it requires a great deal more effort to understand what the second one is doing.  I don't like the first way at all -- but the second way is, if anything, uglier and more complicated.

That's not to say I don't appreciate the code -- I very much do!  You're trying to solve a problem that MS really should have solved itself.  There just doesn't seem to be an easy way to solve it.

Does anyone know if MS has addressed this in .NET 4.0?

Tuesday, July 21, 2009 7:33 PM by Ken Smith

# re: Entity Framework Include with Func next

@Ken, I too wish we had addressed this in .NET 4.0, but unfortunately it didn’t climb to the top of the priority list as we were implementing other features (i.e. POCO support, functions exposed in LINQ, model defined functions, T4 integration, FK support, Contains, DefaultIfEmpty, Single/First/OrDefault, better stored procedure support, ExecuteStoreQuery/Translate, OrderBy Lifting, improvements for StartsWith, optimizations for non-unicode columns, EntityDataSource improvements including LINQ support, etc).

It is hard to get any new feature in for .NET 4.0 at this point, but I promise I will bring it up for the next version.

Thursday, July 23, 2009 3:39 PM by Diego Vega

# re: Entity Framework Include with Func next

Thanks a lot Diego

@Ken: you can simplify a little your code like this:

           Room room2 = ctx.Room
               .Include(r => r.Sessions.Include<Session, User>(s => s.User))
               .Include(r => r.Sessions.Include<Session, Whiteboard>(s => s.Whiteboards).Include(w => w.Owner))
               .Include(r => r.Sessions.Include<Session, Whiteboard>(s => s.Whiteboards).Include(w => w.WhiteboardShape))
               .Include(r => r.Sessions.Include<Session, MediaStream>(s => s.MediaStreams))
               .Include(r => r.Owner)
               .FirstOrDefault(r => r.OwnerID == ownerUserID && r.Name == roomName);

Thursday, July 23, 2009 3:47 PM by Matthieu MEZIL

# re: Entity Framework Include with Func next

I thinkk this is better:

public static ObjectQuery<T,K> Include<T>(this ObjectQuery<T> mainQuery, Expression<Func<T, K>> subSelector)

   {

var sb = new StringBuilder();

       FuncToString(sb, keyExpression.Body);

       return mainQuery.Include(sb.ToString());

   }

       private static void FuncToString(StringBuilder sb, Expression selector)

       {

           switch (selector.NodeType)

           {

               case ExpressionType.Parameter:

//                    sb.Append(((ParameterExpression) selector).Name);

                   return;

               case ExpressionType.MemberAccess:

                   FuncToString(sb, ((MemberExpression) selector).Expression);

                   sb.Append(".");

                   sb.Append(((MemberExpression) selector).Member.Name);

                   return;

           }

           throw new InvalidOperationException();

       }

And now you can use like this:

query.Include(c=>c.Session)

.Incude(c=>c.Session.User)

:)

Thursday, September 17, 2009 7:53 AM by Kamil

# re: Entity Framework Include with Func next

Hi

the problem with your solution is with collection : customers.Include("Orders.OrderDetails")

That's why I did it like this

Matthieu

Thursday, September 17, 2009 8:05 AM by Matthieu MEZIL

# re: Entity Framework Include with Func next

Hello,

Thanks a lot for this code.

I was looking for something like that since I do not want to have strings for names sitting there too.

Now, I only have a strange problem: When I build a query and .Include it passes the data to the FuncToString routine as a ExpressionType.Convert (10) and not one of the three defined to work with.

I added another line to the case section, like this

Case ExpressionType.Convert

Return TryCast(TryCast(TryCast(selector, UnaryExpression).Operand, MemberExpression).Member, Reflection.PropertyInfo).Name (VB Syntax)

which is exactly the same as the .MemberAccess case except for another TryCase selector to UnaryExpression first.

I have no idea what I am doing there, how why what when, but it seems to work. Has anybody a hint why this change is needed, or what I was doing wrong in the first place? Why do I end up with ExpressionType Convert??

I have a second far harder question too: If you have two entities mapped m:n and the middle table of the database does not appear in your entity model (I like that...) I cannot get the function to work at all.

Any hint on that?

Thanks a lot!

Ralf

Thursday, October 22, 2009 3:50 AM by Ralf

# re: Entity Framework Include with Func next

Try with DirectCast instead of TryCast. It was stupid in my case to use the as operator instead a direct cast.

Sunday, November 08, 2009 9:08 AM by Matthieu MEZIL

# Un pattern şi trei implementări (partea 2)

După *** spuneam în postul precedent , fiecare O/RM are propria metodă de a descrie graful de obiecte

Sunday, November 15, 2009 8:27 AM by Tudor Turcu - blog

# re: Entity Framework Include with Func next

I can't get a multiple level path working on Entity Framework 4 with POCO.  The following works:

context.Orders.Include(o => o.OrderItems)

But then if I try:

context.Orders.Include(o => o.OrderItems.Include<OrderItem, OrderItemSub>(s => s.OrderItemSub))

I get the error: cannot convert from ICollection<OrderItem> to EntityCollection<OrderItem>

With POCO, it's ICollection instead of EntityCollection.  Any way to get this working?

Friday, May 07, 2010 9:09 AM by Nelson

# re: Entity Framework Include with Func next

@Nelson.

Good remark.

You just have to change EntityCollection to ICollection in my code.

Let me know if you don't achieve it.

Friday, May 07, 2010 10:09 AM by Matthieu MEZIL

# Bulk Delete only for loaded entities

Update: I made a new version here . In my previous post , I showed you how to do Bulk Update with EF4

Saturday, May 22, 2010 1:13 AM by Matthieu MEZIL

# re: Entity Framework Include with Func next

Hi Matthieu,

just found your awesome include, could have saved me some time. Measnwhile I did my own implementation, maybe you wan't to have a look:

michael-sander.eu/.../strongly-typed-include-in-the-entity-framework

The syntax would be like

from asset in dataContext.Assets

   .Include(x => x.AssetType)

   .Include(x => x.Locations)

   .Include(x => x.Locations.First().MeasuringPoints)

   .Include(x => x.Locations.First().MeasuringPoints.First().MeasuringPointType)

select asset;

which is a bit shorter than yours, but i really dislike the First() calls here.

Wednesday, September 29, 2010 3:40 AM by Micha

# re: Entity Framework Include with Func next

Hi Michael

Yes the syntax is more easy with your fake first.

However, as you, I really dislike the First() calls.

Wednesday, September 29, 2010 5:20 PM by Matthieu MEZIL

# re: Entity Framework Include with Func next

I implemented a similar method with a slightly different approach, using an ExpressionVisitor:

tomlev2.wordpress.com/.../entity-framework-using-include-with-lambda-expressions

Not sure which is better...

Anyway, the EF Feature CTP already provides a method to do the same thing, hopefully it will eventually be included in the framework

Sunday, October 17, 2010 4:57 PM by Thomas Levesque

Leave a Comment

(required) 
(required) 
(optional)
(required) 
If you can't read this number refresh your screen
Enter the numbers above: