正在寻找一种有效的方法,用EntityFrameworkCore为每一行检索一组多对多子级



上下文:我有一个Items表,每个表都有一个多对多的动态描述符集,称为Tags。每个Tag属于一个TagType,它决定了Tag代表什么样的信息(大小、颜色、形状等(。每个Item每个TagType最多只能有一个Tag

目标:如果Item没有TagTypeTag,我想显示一个包含我所有Items的表,并且每行中有一列包含空单元格的<th>TagTypes</th><td>Tags</td>嵌套表。

问题:只有5000个Items的Linq查询至少需要30秒。我预计会有10万+Items。我需要找到一种方法来更有效地填充这些信息。


型号:(省略不相关的属性(

public class Item : BaseEntity
{
public virtual ICollection<ItemTag> ItemTags { get; set; }
}

public class ItemTag
{
public Guid ItemId { get; set; }
public virtual Item  Item {get; set;}
public Guid TagId { get; set; }
public virtual Tag Tag { get; set; }
}

public class Tag : BaseEntity
{
[Required]
[MaxLength(100)]
public string Value { get; set; }
[Required]
public Guid TagTypeId { get; set; }
public virtual TagType TagType {get;set;}
public virtual ICollection<ItemTag> ItemTags { get; set; }
}

public class TagType : BaseEntity
{
[Required]
[MaxLength(50)]
public string Name { get; set; }
public int Position { get; set; }
public virtual ICollection<Tag> Tags { get; set; } 
}

然后我有一个显示模型DisplayItem,我将其转换为Json并返回。

public class DisplayItem
{
public Guid Id { get; set; }
public List<DisplayTag> ItemTags { get; set; }
public DisplayItem(Item itm, IList<TagType> tts)
{
Id = itm.Id;
ItemTags = GetDisplayTags(itm.ItemTags
.Select(it => it.Tag).ToList(), tts);
}
public List<DisplayTag> GetDisplayTags(IList<Tag> tags, IList<TagType> tts)
{
return tts.Select(tt => new DisplayTag(tt.Name, 
tags.FirstOrDefault(t => t.TagTypeId == tt.Id)?.Value ?? "  ")).ToList();
}
}

查询:

public async Task<JsonResult> OnGetItemsAsync()
{
TagTypes = await _context.TagType.OrderBy(tt => tt.Position).AsNoTracking().ToListAsync();
return new JsonResult(await _context.Items
.Include(itm => itm.ItemTags)
.ThenInclude(it => it.Tag)
.ThenInclude(t => t.TagType)
.AsNoTracking()
.Select(itm => new DisplayItem(itm, TagTypes))
.ToListAsync());
}

最慢的部分似乎是GetDisplayTags(itm.ItemTags.Select(it => it.Tag).ToList(), tts);,但我不确定我还能怎么获得这些信息。

OnGetItemsSync中的查询不知道DisplayItem构造函数中发生了什么,所以您的查询返回了整个Items集合,每个Item的ItemTags集合,每个ItemTag的Tags集合和每个Tag的TagType集合,所以您带回了很多不必要的数据。为了防止这种情况,您应该从查询中删除includes。此外,您还可以优化查询,这在您看来是最慢的部分。FirstOrDefault每次都会在整个集合中搜索一个马赫。你可以试试

return tts.Select(tt => new DisplayTag(tt.Name, tags.Where(t=>t.TagTypeId==tt.Id).GroupBy(t=>t.TagTypeId).Select(tg=>tg.First()?.Value??" "))).ToList();

然后查询将返回TagTypeId的集合,并且不必在整个集合中搜索第一个条目。

最新更新