views:

100

answers:

2

Having two classes like Blog and Post, in Entity Framework (and LINQ-to-Entities), how can you get the blogs with the posts sorted by date. I was getting the blogs with the posts this way:

from blog in db.BlogSet.Include("Posts") select blog

and now I'm forced to do this:

public class BlogAndPosts {
    public Blog Blog { get; set; }
    public IEnumerable<Post> Posts { get; set; }
}

from blog in db.BlogSet
select new BlogAndPosts () {
    Blog = blog,
    Posts = blog.Posts.OrderByDescending(p => p.PublicationTime)
}

which is very convoluted and ugly. The reason why I'm creating a BlogPosts class is that now, since I have to pass two variables, Blog and Posts, to MVC, I need a view model.

I'm even tempted to try this hack:

from blog in db.BlogSet
select new Blog(blog) {
    Posts = blog.Posts.OrderByDescending(p => p.PublicationTime)
}

but what's the correct way to do it? Is Entity Framework not the way to go with MVC?

+2  A: 

I generally create a presentation model type wholly unaware of the Entity Framework and project into that. So I would do something like:

public class PostPresentation {
    public Guid Id { get; set; }
    public string Title { get; set; }
    public DateTime PostTime { get; set; }
    public string Body { get; set; }
}

public class BlogHomePresentation {
    public string BlogName { get; set; }
    public IEnumerable<Post> RecentPosts { get; set; }
}

from blog in db.BlogSet
select new BlogHomePresentation 
{
    BlogName = blog.name,
    RecentPosts = (from p in blog.Posts
                   order by p.PublicationTime desc
                   select new PostPresentation 
                   {
                       Id = p.Id,
                       Title = p.Title,
                       PostTime = p.PublicationTime,
                       Body = p.Body
                   }).Take(10)
}

Does this seem like a lot of work? Consider the advantages:

  1. Your presentation is entirely ignorant of your persistence. Not "ignorant as in having to make all of the properties public virtual," but entirely ignorant.
  2. It is now possible to design the presentation before designing the database schema. You can get your client's approval without doing so much work up front.
  3. The presentation model can be designed to suit the needs of the page. You don't need to worry about eager loading or lazy loading; you just write the model to fit the page. If you need to change either the page or the entity model, you can do either one without affecting the other.
  4. Model binding is easier with simple types. You will not need a custom model binder with this design.
Craig Stuntz
Just for the record, I don't think doing this makes sense except to workaround Entity Framework. Using any other ORM I wouldn't extract related objects and put them in a class; I would put in a class totally independent data though. At any rate, it works, so I'm accepting it.
J. Pablo Fernández
A: 

I would also suggest to use view models. When your application grows, there may be more content on a specific view, like:

public class PostDetailResult {
    public Post<Post> Post { get; set; }
    public IList<Post> RecentPosts { get; set; }
    public IList<Post> RelatedPosts { get; set; }
    public IList<Post> MostRated { get; set; }      
}

You may add another layer between controller and data abstraction like a repository, because your BL should decide what "MostRated" posts are. If you are using "MostRated" posts on multiple views you don't want to write the same query in multiple controllers. With a repository, controller code might look like this:

var result = new PostDetailResult { 
    Post = repo.GetPost(id),
    RecentPosts = repo.GetRecentPosts(),
    RelatedPosts = repo.GetRelatedPosts(id)
};

Hope, this helps.

Claus Trojahn