C# LINQ 联接与投影

本文关键字:投影 LINQ | 更新日期: 2023-09-27 17:56:13

所以在我的商店应用程序中,我允许用户收藏物品。我希望做的是在用户配置文件页面中显示收藏夹项目列表,其中列表按相同日期降序排序。

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

如何连接这两个表,因此结果将回答以下条件:

  1. 结果将是此特定用户收藏的项目列表。

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

  3. 结果将正确排序。

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

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();

这有效,但不回答第一个条件,即仅返回特定用户喜欢的项目,这将返回用户而不是特定用户喜欢的项目列表。

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

C# LINQ 联接与投影

解决此问题的一种方法是:

  • 包括用户 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集合将包含您需要的所有数据,因此您必须将其投影到适合您需求的结构中。

注意,我之前提到过哪个有效,因为我不完全确定GroupJoin是否正确转换为 SQL,并且我不确定我是否错过了 GroupJoin 方法的一些要求。