上下文:我有一个Items
表,每个表都有一组称为Tags
的动态描述符多对多。每个Tag
都属于一个TagType
,该Tag
确定Item
代表哪种信息(大小,颜色,形状等)。每个Tag
每个TagType
最多只能有一个Items
。
目标:我想显示我所有<th>TagTypes</th>
的表,并在每行中都有一列,其中<td>Tags</td>
和Item
的嵌套表具有空单元格,如果Tag
没有表示该TagType
。
问题:Linq查询仅用5000 Items
花费至少30秒。我期望有100k + 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);
,但是我不确定我还怎么去获取这些信息。 最佳答案
您在OnGetItemsAsync中的查询不知道,DisplayItem构造函数中会发生什么,因此您查询返回整个Items集合,每个Item的ItemTag集合和每个ItemTag的Tag集合以及每个Tag的TagType集合,因此您带回很多不必要的数据。为了防止这种情况,您应该从查询中删除包含。
您还可以优化查询,这似乎是最慢的部分。每次在整个集合中搜索一个mach的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的集合,而不必在整个集合中搜索第一个条目。