繁体   English   中英

连接多个列,其中一列在一个表中可以为空,但在另一个表中不能为空

[英]Join multiple columns where one column is nullable in one table but not the other

我有一个查询需要连接多个列,其中一个列现在在其中一个表中可以为空。

    var personAchievement = await _context.Achievements
        .Join(_context.Persons, a => new { a.Region, a.PersonNumber }, p => new { p.Region, p.PersonNumber }, (achievement, person) => new { Achievement = achievement, Person = person })
        .Where(_ => _.Achievement.PersonNumber != null)

Persons表使用Region (数据库中的 varchar 和我的模型中的字符串)和PersonNumber (数据库和模型中的 int)作为复合唯一 ID。 这两个字段用于许多表,这些表连接到 Person 用于各种事情。 一个表, Achievements ,需要使PersonNumber字段可以为空,以便添加其他类型的具有成就的实体。 这个查询已经像上面一样工作了很长时间,直到今天我在Achievements model 上将该字段设置为可为空的 int。

它打破的一个地方是匿名构造函数a => new { a.Region, a.PersonNumber } 连接失败说这两种匿名类型“不能从使用中推断出来”,因为它不能将int转换为int? 含蓄地。 如果我尝试将 PersonNumber 装箱或转换为不可为空的 int,或在其上使用.Value ,匿名构造函数将失败,因为您只能使用标准的简单类型来构造匿名对象。

有没有办法用 EF Core 3.1 做到这一点? 也许通过欺骗 EF 以某种方式将两个值都转换为字符串(我已经能够在 DB 查询中做到这一点)?

我看到人们遇到这个问题的常见情况是由于不正确的规范化。 要求就像我们想要一个可以与个人或公司相关联的成就作为示例,所以我们要么得到类似的东西:

[Achievement]
AchievementId (PK)
PersonId (FK, Nulable)
CompanyId (FK, Nullable)

或者

[Achievement]
AchievementId (PK)
LinkId 
LinkType /* I.e. PERSON or COMPANY */

这两种设计都有潜在的严重问题,尤其是随着系统的发展。

第一种情况可以使用 EF 中的导航属性进行管理,然后查询特定人员的成就:

var achievements = _context.Achievements
    .Include(a => a.Person)
    .Where(a => a.Person.PersonNumber == personNumber && a.Person.Region == region)
    .ToList();

从那里您可以使用achievement.Person访问 Person 。 或者,如果您需要该匿名类型:

var data = _context.Achievements
    .Where(a => a.Person.PersonNumber == personNumber && a.Person.Region == region)
    .Select new {Achievement = a, Person = a.Person})
    .ToList();

EF 应该能够在没有太多麻烦的情况下解决这些关系,除非架构或实体中没有任何内容来确保不能将相同的成就分配给个人和公司。 任何类似的限制都需要在代码中强制执行。

第二种选择相当普遍,但老实说,这两种情况中最糟糕的一种。 这就是 LinkId 或 ParentId 之类的东西保存可能是个人 ID 或公司 ID 的值的地方。 虽然这确实有助于确保成就可能只与一个或另一个相关联(并且会解决您的类型不匹配),但更大的问题是您无法为该关系设置关系 FK,因此数据库中没有任何内容实际上可以保证LinkId 实际上确实指向一条记录。 如果由于错误或其他恶意代码/SQL 导致 LinkType 碰巧被篡改,您可能会看到一个成就指向一个完全不相关的实体。 性能方面也是如此,如果没有 FK,这将随着系统的增长而开始爬行,并且所有成就最终都在同一个表中。

另一个考虑因素是保证成就不会有条件值,具体取决于它们是否与个人或公司或......(将来可能添加的任何内容)相关联的成就是一个单一的表,其中就其所需的数据而言,所有成就都是平等的。 如果与人员关联的成就预计会填充一组特定字段,但与公司关联的成就不需要这些字段,则这些实体/表应分为 PersonalAchievement 和 CorporateAchievement 之类的内容,即使 95 % 的列是相同的。

将数据整合到单个表中的吸引力来自于存储空间昂贵的时代。 但即便如此,你也在设计中的不同弊端之间进行交易。 在一个表中保存 100,000 行与在两个表中保存 20,000 行和 80,000 行实际上与存储容量没有区别,但从索引和约束的角度来看却大不相同。 使用单独的表意味着您可以强制实施适用的约束并使用匹配的键。 合并表就像多态性一样,多个实例可以被同等对待,而不仅仅是同等对待是有意义的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM