在 child table 中取一个并跳过其他重复项

Take one and skip other duplicate item in a child table

我有一个项目列表,每个项目都有一些列表,现在我想要 select child 个不同的项目。我试过如下,但没有用。

var items = await _context.Items.
Include(i => i.Tags.Distinct()).
Include(i => i.Comments).
OrderBy(i => i.Title).ToListAsync();

//Tag items
TagId    -   tag
------------------
  1   ---   A 
  2   ---   B 
  3   ---   B 
  4   ---   C 
  5   ---   D 
  6   ---   D 
  7   ---   F
//Expected Result
Item.Tags -> [A,B,C,D,F]

如何在 EF Core 中执行此操作?谢谢

您可以使用 MoreLinq library to get DistinctBy or write your own using this post.

然后使用这个:

var items = await _context.Items.
    Include(i => i.Tags).
    Include(i => i.Comments).
    OrderBy(i => i.Title).
    DistinctBy(d => d.Tags.tag).
    ToListAsync();

您想根据一列获得不同的记录;所以应该这样做。

显然你有 Items 个 table,其中每个 Item 有零个或多个 Tags。此外 Items 有一个 属性 Comments,我们不知道它是一个字符串,还是零个或多个字符串的集合。此外,每个 Item 都有一个 Title.

现在您需要项目的所有属性,每个属性都有其 Comments,以及项目的唯一 Tags 列表。由 Title

订购

数据库查询中速度较慢的部分之一是将所选数据从数据库管理系统传输到本地进程。因此,明智的做法是将数据量限制在您实际使用的最低限度。

ItemsTags 似乎在单独的 table 中。每个 Item 有零个或多个 Tags,每个 Tag 只属于一个项目。带有外键 Tag.ItemId.

的简单一对多关系

如果ItemId300有1000个Tags,那么就知道这1000个Tags每一个都有一个外键ItemId你知道它的值为 300。如果你将所有这些外键传输到你的本地进程,那真是浪费。

Whenever you query data to inspect it, Select only the properties you really plan to use. Only use Include if you plan to update the included item.

因此您的查询将是:

var query = myDbContext.Items
    .Where(item => ...)                // only if you do not want all items
    .OrderBy(item => item.Title)       // if you Sort here and do not need the Title
                                       // you don't have to Select it
    .Select(item => new
    {   // select only the properties you plan to use
        Id = item.Id,
        Title = item.Title,
        Comments = item.Comments,      // use this if there is only one item, otherwise
        Comments = item.Comments       // use this version if Item has zero or more Comments
           .Where(comment => ...)      // only if you do not want all comments
           .Select(comment => new
           {   // again, select only the Comments you plan to use
               Id = comment.Id,
               Text = comment.Text,

               // no need for the foreign key, you already know the value:
               // ItemId = comment.ItemId,
           })
           .ToList();

           Tags = item.Tags.Select(tag => new
           {   // Select only the properties you need
               Id = tag.Id,
               Type = tag.Type,
               Text = tag.Text,

               // No need for the foreign key, you already know the value
               // ItemId = tag.ItemId,
           })
           .Distinct()
           .ToList(),
     });

var fetchedData = await query.ToListAsync();

我没试过,但我会说你把 .Distinct() 放错地方了。

var items = await _context.Items
        .Include(i => i.Tags)
        .Include(i => i.Comments).
        .OrderBy(i => i.Title)
        .Select(i => { i.Tags = i.Tags.GroupBy(x => x.Tag).Select(x => x.First()); return i; })
        .ToListAsync();