开发者

Sort child entities while selecting the parents

I have these classes:

public class WallPost
    {
        public long WallPostId { get; set; }

        [Required]
        public long UserId { get; set; }
        [Required]
        public long WallUserId { get; set; }
        [Required]
        public string PostText { get; set; }
        public DateTime CreatedOn { get; set; }

        public virtual User WallUser { get; set; }
        public virtual User User { get; set; }
        public virtual ICollection<WallPostReply> WallPostReplies { get; set; }

    }

 public class WallPostReply
    {
        [Key]
        public long ReplyId { get; set; }

        [Required]
        public long UserId { get; set; }
        [Required]
        public long WallPostId { get; set; }
        [Required]
        public string ReplyText { get; set; }
        [Required]
        public DateTime CreatedOn { get; set; }


        public virtual WallPost WallPost { get; set; }
        public virtual User User { get; set; }
    }

And in a method I get all wall posts sorted by CreatedOn:

public IEnumerable<WallPost> GetMorePosts(long wallUserId, int pageNumber, bool showOnlyMyPosts)
        {   
            var wallUser = _db.Users.Where(x => x.UserId开发者_C百科 == wallUserId).FirstOrDefault();
            var postEntries = wallUser.MyWallPosts.Where(x => x.UserId == wallUser.UserId || showOnlyMyPosts == false).OrderByDescending(x => x.CreatedOn)
                .Skip(5 * pageNumber).Take(5);

            return postEntries;
        }

What I want to do is to get also the WallPostReplies child entities sorted by CreatedOn as well, how to write this in the same query?


First of all your second query is linq-to-objects, not linq-to-entities - it will always load all users's posts and make filtering and ordering on your application server. Next you don't explicitly load replies so once you start browsing them you will have separate lazy loading query for each post => N + 1 problem.

It is not possible directly sort child entities when loading data with linq-to-entities. You must use projection to anonymous type:

var query = _db.WallPosts
               .Where(x => x.UserId == userId)
               .OrderByDescending(x => x.CreatedOn)
               .Skip(5 * pageNumber)
               .Take(5);
               .Select(x => new 
                   {
                      Post = x,
                      Replies = x.WallPostReplies.OrderBy(y => y.CreatedOn)
                   });

So one more try: You cannot get WallPosts instances with sorted related entities (WallReplies) from linq-to-entities. You must make projection to WallPosts in linq-to-objects:

IEnumerable<WallPosts> posts = query.AsEnumerable()
                                    .Select(x => new WallPost
                                        {
                                            WallPostId = x.Post.WallPostId,
                                            UserId = x.Post.UserId,
                                            WallUserId = x.Post.WallUserId,
                                            PostText = x.Post.PostText,
                                            CreatedOn = x.Post.CreatedOn,
                                            Replies = x.Replies
                                        });


I had a similar problem at one point .. If I understand you right, you first want a list of posts then for each post you want a list of replies?

So first we get the posts in question ...

//gets posts ... 
public IEnumerable<WallPost> GetMorePosts(long wallUserId, int pageNumber, bool showOnlyMyPosts)         {                
    WallUser wallUser = _db.Users.Where(x => x.UserId == wallUserId).FirstOrDefault() as WallUser;             
    IEnumerable<WallPost> results = 
       (from post in wallUser.MyWallPosts where post.UserId == wallUser.UserId  showOnlyMyPosts == false order by post.CreatedOn descending)
         .Skip(5 * pageNumber)
         .Take(5);              

    return results.ToList();         
    } 

Then we get the replies ...

// gets replies

IEnumerable<WallPost> posts = GetMorePosts(userid, pageNo, showonlyMine);
foreach(WallPost post in posts)
{
  IEnumerable<WallPostReply> replies = (from reply in post.WallPostReplies order by reply.CreatedOn select reply).ToList();
  // do something with post and the order list of replies
}  

In short ... my advice ... don't try to do too much at once!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜