If you use the Entity Framework in your .Net applications then you should know that accessing child objects of an object model that depends on data from a database forces an ADO.Net call to occur at the time that it is accessed at run time. This is referred to as lazy loading. Imagine the following example:

public class Users  
{
    public int Id { get; set; }
    public UserType UserType { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Post> Posts { get; set; }
}

public class PostMap : EntityTypeConfiguration<Post>  
{
    public PostMap()
    {
        ...
        // Relationships
        this.HasRequired(t => t.User)
            .WithMany(t => t.Posts)
            .HasForeignKey(t => t.UserId);
        ...
        }
    }

The Entity Framework will manage the Posts relationship for us in this model because of the mapping that has been set up. What it will not do is optimize our access to the database in a situation where a large volume of attempts to utilize this property occur. Now consider the following example:

using (DatabaseContext context = new DatabaseContext)  
{
    List<User> users = context.Users.Where(x => x.Id < 100).ToList();
    foreach(var user in users)
    {
        List<Post> posts = user.Posts.ToList();
    }
}

In this situation, lazy loading is not the ideal way to handle retrieving the Posts because for each User we iterate over an additional request will be made to the database to retrieve all the Posts. The solution to this problem is as follows:

using (DatabaseContext context = new DatabaseContext)  
{
    List<User> users = context.Users.Where(x => x.Id < 100)
                                    .Include(x => x.Posts).ToList();
    foreach(var user in users)
    {
        List<Post> posts = users.Posts.ToList();
    }
}

By using .Include() we have eager loaded that property and all the associated data, resulting in only 1 database call. To include a property that is a child of a collection object you would do the following:

.Include(x => x.Posts.Select(y => y.Tags));

At Second Street, we have adopted a message design pattern for communicating with the service layer of our applications to provide greater flexibility. In practice, our service layer requests are more tiered than the examples I have shown above. Our service request objects are setup like this:

public abstract class ServiceRequestBase<T> : ServiceRequestBase, IServiceRequest<T> where T : EntityBase  
    {
        ...
        public Expression<Func<T, bool>> Criteria { get; set; }
        public List<Expression<Func<T, object>>> IncludePathExpressions { get; set; }
        ...

        public ServiceRequestBase()
        {
            ...
            this.IncludePathExpressions = new List<Expression<Func<T, object>>>();
            ...
        }

        public void AddIncludePathExpressions(params Expression<Func<T, object>>[] includePathExpression)
        {
            this.IncludePathExpressions.AddRange(includePathExpression);
        }
    }

A practical usage of a request object would look like this:

    ...
    UserRequest userRequest = new UserRequest();
    userRequest.Criteria = (x => x.Id < 100);
    userRequest.AddIncludePathExpressions((x => x.Posts));
    List<User> users = _userService.GetUsers(userRequest).Entities.ToList();
    ...

Later on in the UserService the UserRequest properties would be added using the .Include() method.

...
if (request.IncludePathExpressions != null && request.IncludePathExpressions.Any())  
{
    foreach (var path in request.IncludePathExpressions)
    {
        query = query.Include(path);
    }
}
...