簡體   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