考虑联合会、冠军赛和球队的场景,一个联合会有很多冠军,一个冠军有很多球队。在创建联合会的同时,必须同时创建其锦标赛。因此,要检查数据库中是否已存在联盟,我需要比较冠军值而不是 ID,这意味着比较球队列表。如何以实体框架可以转换的方式在查询中执行此操作?
我的询问:
_context.Confederations
.Where(c => c.Championships
.Where(ch => newConfederation.Championships
.Where(ca => ca.Teams
.Where(t => ch.Teams.Any(te => te.Id == t.Id))
.Count() == ch.Teams.Count())
.Any())
.Count() == newConfederation.Championships.Count)
.Any();
听起来您想支持插入一个由锦标赛和球队组成的联合会,但请检查现有的匹配安排。假设球队记录可以参加多个锦标赛,那么进行这样的比较的一种方法是从锦标赛中提取唯一值,例如冠军年份和关联的球队 ID 到一个更具可比性的结构中,然后为该锦标赛构建相同的结构您要插入的数据并进行比较。我们需要一个独特的、可比较的冠军值,因为在构建可比较的字符串时,我们需要确保这些值的排序一致。如果双方都是唯一的匹配引用,我们可以使用 TeamId,但可能会生成任何冠军 ID,因此我们需要诸如冠军年份之类的内容来进行比较。
例如:
var existingConfederations = _context.Confederations
.Select(x => new
{
x.ConfederationId,
Championships = x.Championships
.OrderBy(c => c.Year)
.Select(c => new
{
c.Year,
TeamIds = c.Teams
.OrderBy(t => t.TeamId)
.Select(t => t.TeamId)
.ToList()
}).ToList()
}).ToList()
var existingRows = existingConfederations
.Select(x => string.Join(",", x.Championships
.Select(c => $"[{c.Year}|{string.Join("-", c.TeamIds)}]")
.ToList()).ToList();
这是一个双重投影,第一步是按年份获取所有现有联盟,以获得它们的年份和有序团队 ID 的列表。第二步是针对每个联合会,为每个冠军构建一个字符串,该字符串应类似于:
[2020|1-3],[2021|4-23],[2022|2-19]
[2019|2-3].[2020|5,11]
基本上每一行都是一个联盟,其中包含各种有序的冠军年份以及该冠军中的球队 ID。
然后对您的新联盟执行相同的操作,构建匹配字符串以比较锦标赛和球队:
var newRow = string.Join(",", existingConfederation.Championships
.OrderBy(c => c.Year)
.Select(c => $"[{c.Year}|{string.Join("-", c.Teams.OrderBy(t => t.TeamId).Select(t=> t.TeamId)}]")
.ToList());
现在我们可以将其与从数据库中读取的联合会冠军字符串进行比较:
var isDuplicate = existingRows.Contains(newRow);
因此,如果这构建了一个字符串“[2020 | 1-3],[2021 | 4-23],[2022 | 2-19]”,并且与为数据库中的某个联盟构建的字符串相匹配那么我们就有了重复的匹配。请注意,这仅检查相同的匹配项。如果存储的联盟有一个额外的冠军或一个不同的球队 ID,这些联盟将不匹配,因此要非常确定查找重复项的业务要求。在构建要比较的结构时,无论是要迭代的字符串还是集合,重要的是在两侧对数据进行一致的排序。
这种方法的缺点是它确实涉及将所有联合会/锦标赛具体化到内存中,因此它不是一种适合极大数据集的方法。然而,在这种情况下,我们只阅读最少量的信息。 (年份和团队 ID)
看看这是否能给您一些关于如何检查重复项的想法。