c#linq与投影联合

时间:2016-07-08 14:41:26

标签: c# sql linq

所以在我的商店应用程序中,我允许用户喜欢的商品。 我想要做的是在用户个人资料页面中显示最喜欢的项目列表,其中列表按照降序排列在相似的日期。

我们需要加入2个表,一个是项目,另一个是收藏夹。

如何加入这两个表,结果将回答这个标准:

  1. 结果将是此特定用户最喜欢的项目列表。

  2. 结果将附带每个项目的评论列表(每个项目都有一个评论列表)。

  3. 结果将正确排序。

  4. 到目前为止,我想出了这个:

    Items =
                 await _context.Favorites
                 .Join(
                     _context.Items,
                     f => f.ItemId,
                     i => i.Id,
                     (f, i) => new { f, i }) 
                     .Distinct()
                     .OrderByDescending(x => x.f.FavDate)
                     .Select(x => x.i)
                     .Skip(skip).Take(take)
                     .Include(c => c.ListOfComments)
                     .ToListAsync();
    

    这有效,但没有回答第一个标准,即只返回特定用户最喜欢的项目,这将返回用户喜欢的项目列表,而不是特定用户的列表。

    我试图在连接之前添加一个where子句(_context.Favorites.Where(f.UserVoterId.equals(profileId))但它会抛出异常。

1 个答案:

答案 0 :(得分:0)

解决这个问题的一种方法是:

  • 包含用户ID作为连接键和
  • 分步加载数据

要选择特定用户(profileId)的收藏项,您需要此查询:

var favorites = _context.Favorites.OrderByDescending(f => f.FavDate)
    .Join(_context.Items,
        fav => new { fav.ItemId, UserId = fav.UserVoterId },
        item => new { ItemId = item.Id, UserId = profileId },
        (fav, item) => item)
    .Skip(pageIndex * pageSize)
    .Take(pageSize)
    .ToList();

要加载评论,只需尝试以下其中一项(无论哪种方法):

var itemIds = favorites.Select(f => f.Id);
var comments = _context.Comments.Where(c => itemIds.Contains(c.ItemId))
    .GroupBy(c => c.ItemId)
    .ToDictionary(g => g.Key, g => g.ToArray());

或者

var items = _context.Comments
    .GroupJoin(favorites,
        comment => comment.ItemId,
        favorite => favorite.Id,
        (fav, comments) => new
        {
            Item = fav,
            Comments = comment.ToArray()
        });

在第一种情况下,评论会添加到Dictionary<TItemId, Comment>,其中TItemIditem.Id的类型,并获取您使用的项目的评论

var itemComments = comments[item.Id];

这是O(1)操作。

在第二种情况下,items集合将包含您需要的所有数据,因此您必须将其投影到符合您需求的结构中。

NB 我之前提到无论哪个,因为我不完全确定GroupJoin是否已正确转换为SQL而且我不确定是否错过了GroupJoin方法的一些要求。