EF CTP4 Tips & Tricks: Include with Lambda

Posted on July 14, 2010. Filed under: Entity Framework, Visual Studio | Tags: , , , , |

The release of Entity Framework Feature CTP4 was recently announced and included some walkthroughs touching on the core functionality included in the CTP. Over the next couple of weeks I’m going to post up a series of short articles that cover some of the finer points in the CTP.

The CTP includes some work called the Productivity Improvements for EF which aims to provide a simpler and more productive experience writing data access code with EF. Along with a bunch of conventions that take care of a lot of common tasks the Productivity Improvements also include some more subtle improvements over the core EF API. One of these is the introduction of an Include method that uses a lambda rather than strings to specify the include path.

Building a Quick Model

With the productivity improvements I can define a model using a set of POCO classes:

public class Blog 
{ 
    public int BlogId { get; set; } 
    public string Title { get; set; }

    public ICollection<Post> Posts { get; set; } 
}

public class Post 
{ 
    public int PostId { get; set; } 
    public string Title { get; set; } 
    public string Content { get; set; }

    public Blog Blog { get; set; } 
    public ICollection<Comment> Comments { get; set; } 
}

public class Comment 
{ 
    public int CommentId { get; set; } 
    public string CommentText { get; set; }

    public Post Post { get; set; } 
}

With the classes defined I just need to write a simple context:

public class BlogContext : DbContext 
{ 
    public DbSet<Blog> Blogs { get; set; } 
    public DbSet<Post> Posts { get; set; } 
    public DbSet<Comment> Comments { get; set; } 
}

Then I can use it for data access and EF will take care of discovering my model and creating a database for me:

using (var context = new BlogContext()) 
{ 
    foreach (var blog in context.Blogs) 
    { 
        Console.WriteLine(blog.Title); 
    } 
}

Existing Include

Include is a method we use in queries to specify that we should load related entities as well as the main type we are querying for, i.e. I want to query for a Blog but I want to bring all the Comments back into memory at the same time.

In EF4 (.NET 4.0, Visual Studio 2010) Include accepts a string to specify the related properties that should be loaded:

var blogsWithPosts = context.Blogs.Include("Posts");

The main complaints with this are the lack of intellisense, lack of compile time checking and that using refactoring in Visual Studio to rename the Blog.Posts property won’t update the string. Include was also an instance method on ObjectSet<T> so it had to be the first call when chaining query methods and wasn’t available if you’re set was typed as IObjectSet or IQueryable.

Include with Lambda

CTP4 includes a version of Include that accepts a lambda to specify the property to include. Note that this version of Include is an extension method so you will need to add a using for the System.Data.Entity namespace.

var blogsWithPosts = context.Blogs.Include(b => b.Posts);

This version of Include is an extension method on IQueryable<T> so you can add it after chaining other query methods:

var blogsWithPosts = context.Blogs 
    .Where(b => b.Title.StartsWith("A")) 
    .OrderBy(b => b.Title) 
    .Include(b => b.Posts);

Obviously not all implementations of IQueryable support Include, the implementation in CTP4 is EF specific and supports ObjectSet<T>, ObjectQuery<T> and DbSet<T> based queries. If the underlying implementation of IQueryable is something else then the extension method checks for a string based Include method to call, if there isn’t one then it is effectively a no-op.

Multi-Level Includes

Including more than one level in a hierarchy is still possible with the lambda Include, for reference properties you just dot through the hierarchy:

var commentsWithPostAndBlog = context.Comments.Include(c => c.Post.Blog);

For collections you use the Select method:

var blogsWithPostsAndComments = context.Blogs.Include(b => b.Posts.Select(p => p.Comments));

Summary

EF Feature CTP4 includes a new Include extension method in the System.Data.Entity namespace that allows you to specify include paths with a lambda. The Include extension method works with the new DbSet<T> along with existing ObjectSet<T> and ObjectQuery<T> types. This approach to specifying includes gives a better intellisense experience along with property name refactoring in Visual Studio and compile time checking of the include path.

About these ads

Make a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

25 Responses to “EF CTP4 Tips & Tricks: Include with Lambda”

RSS Feed for RoMiller.com Comments RSS Feed

[...] Feature CTP4, also recently dubbed “EF Magic Unicorn Edition”. In the last post we looked at Include with lambda and today we are going to look at the new Find [...]

public ICollection Posts { get; set; }

Can you explain how to add new Post to uninitialized collection?

Might be this must be look like:

private ICollection posts;
public ICollection Posts { get { return posts ?? ( posts = new Collection()); }}

??

Thanks.

@Roman
The pattern you described is a common one, another alternative is to initialize the collection properties in the constructor. The pattern you suggested will potentially give better performance in situations where you are constructing a large number of objects because you only create the collection when actually needed.

I normally use List for the collection properties but you can of course use anything that implements ICollection.

EF doesn’t require that you initialize collections and will do it for you when it needs to add to the collection property (which is why the code in the post works).

[...] EF CTP4 Tips & Tricks: Include with Lambda [...]

[...] EF4 .Include() Method w/ Lambda Support: Ever wanted to use a Lambda expression instead of a string parameter when eagerly loading associations in EF4 using the Include() method?  This blog post shows you how you can. [...]

[...] EF4 .Include() Method w/ Lambda Support: Ever wanted to use a Lambda expression instead of a string parameter when eagerly loading associations in EF4 using the Include() method?  This blog post shows you how you can. [...]

Will this support Include and a Where clause? Like:

.Include(b => b.Posts.Where(x=> x.Status == “Active”));

or something else like that?

WOW!
You didn’t mention that in your blog!
That’s most compelling, finally!!!

@weitzhandler & @John Bloom
We would like to support filtering with Where in the future, which is why we opted for Select rather than Single.
But it’s not there in CTP4.

Now that’s what I’ve been waiting for,very nice.

After rviewing this post I am still saying that the Select (“For collections you use the Select method”) should have been shorter, why use a new lmbda when this can be done in one word?
View my blog http://blogs.microsoft.co.il/blogs/shimmy
Even Single() is not the rightest way, an extra lambda is surely not.
I guess it’s too late anyway.

I can not see the strongly typed version of Include? I have EF4 (.Net 4) and VS2010, its still exposing the string based Include.

@James:
Because you didn’t notice this in the article:
“Note that this version of Include is an extension method so you will need to add a using for the System.Data.Entity”.

That means you have to add:

Using System.Data.Entity;

I’m the one who posted this reply :)

No, I’m the one who posted this reply!

@James
You also need to have EF Feature CTP4 installed as the lambda based include is still in preview; http://blogs.msdn.com/b/adonet/archive/2010/07/14/CTP4Announcement.aspx
~Rowan

[...] méthode d’extension similaire est inclue dans le Entity Framework Feature CTP4 (voir cet article pour plus de détails). Il est donc probable qu’elle finisse par être intégrée dans le [...]

[...] similar extension method is included in the Entity Framework Feature CTP4 (see this article for details). So it is possible that it will eventually be included in the framework (perhaps in a [...]

[...] · EF4 .Include()函数对Lambda的支持:在EF4里用Include()函数加载关联数据时,想用Lambda表达式替换字符参数?这篇文章就教你怎么做。 [...]

Question on creating a DBContext derived context: is it necessary to declare a DbSet property for each entity class you create? For instance, if I have a Members entity and a MemberProfiles entity, but since a profile can belong only to one member and a member can only have one profile, they share an id field (MemberId). I would only access the profile data through the Member entity. Therefore, do I need to create a property DbSet MemberProfiles { get; set; }?

BTW,an excellent series. Actually the most clear, concise, comprehensive one I’ve been able to find on the Internet, to date.

Hi Craig,

You can include extra entities that are not exposed in a DbSet in the OnModelCreating method:

public class MemberContext : DbContext
{
public IDbSet Members { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity();
}
}

Hope this helps,
~Rowan

I’m trying to use this on EF4 and VS2010.
I’ve included the
using System.Data.Entity;
but still has the only string version of include. Am I missing something ?

I would like to use Multi-Level Includes what you proposed, but I could not user more than one relatives. Does Include support only on relation?
Thanks in advance.

[...] méthode d’extension similaire est inclue dans le Entity Framework Feature CTP4 (voir cet article pour plus de détails). Il est donc probable qu’elle finisse par être intégrée dans le [...]


Where's The Comment Form?

Liked it here?
Why not try sites on the blogroll...

Follow

Get every new post delivered to your Inbox.

Join 159 other followers

%d bloggers like this: