嘗試使用物體框架 (CRUD) 為我的 Player 模型添加 Razor 頁面時,出現以下例外
Unable to determine the relationship represented by navigation 'Player.Alliance' of type 'Alliance'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'
public class Player
{
public Guid PlayerID { get; init; }
// Navigation properties
public virtual Alliance Alliance { get; init; }
// Properties
public int GovernorIdentifier { get; set; }
public string Name { get; set; }
public int Power { get; set; }
public int Killpoints { get; set; }
public Civilization Civilization { get; set; }
public int HighestPower { get; set; }
public int Victory { get; set; }
public int Defeat { get; set; }
public int Dead { get; set; }
public int ScoutTimes { get; set; }
public int ResourcesGathered { get; set; }
public int ResourceAssistance { get; set; }
public int AllianceHelpTimes { get; set; }
}
public class Alliance
{
// Primary key
public Guid AllianceID { get; init; }
// Navigation properties
public Player Leader { get; init; }
public ICollection<Player> Players { get; init; }
// Properties
public string Tag { get; set; }
public string Name { get; set; }
public int Territories { get; set; }
public int GiftLevel { get; set; }
public int PlayerCapacity { get; set; }
}
當我public Player Leader { get; init; }從Alliance中洗掉或public virtual Alliance Alliance { get; set; }從 Player 中洗掉時,錯誤已解決。
如何在玩家和聯盟之間實作雙向一對一(如果這是錯誤的術語,請不要殺了我)關系?在我的特定用例中,我如何確保 Alliance 擁有玩家串列和作為聯盟領導者的玩家的導航屬性,并且 Player 具有與其所屬聯盟的導航屬性?
uj5u.com熱心網友回復:
當您依賴 EF 約定來映射關系時,就會發生這種情況。問題出在您的聯盟物體/表中。你有:
public Player Leader { get; init; }
public ICollection<Player> Players { get; init; }
在您的玩家中,您將有一個 AllianceId,EF 將使用它來決議與聯盟關聯的玩家,但您的聯盟表還需要一個 FK 來決議作為領導者的玩家記錄。
EF 可以按照約定計算出多對一的鍵,但它是根據型別名稱而不是屬性名稱來計算的。在您的 Alliance 表中,您可能有類似 LeaderId 的東西,或者更好的是 LeaderPlayerId。EF 不會自動解決此問題,因此您需要顯式映射它。
對于 EF Core,如果您不想將 FK 作為 Alliance 中的屬性公開,則可以使用影子屬性。(我建議不要在導航屬性旁邊公開 FK 以避免兩個事實來源)根據您使用的映射方法,無論是使用OnModelCreating/w modelBuilder 還是IEntityTypeConfiguration,或者依賴約定,您都可以設定 FK 影子屬性:
使用屬性的約定:
[ForeignHey("LeaderPlayerId")]
public virtual Player Leader { get; set; }
使用 modelBuilder 或 EntityTypeConfiguration,您可以使用.HasForeignKey("LeaderPlayerId")運算式.HasOne(...).WithMany()。
這里的限制是,通過跟蹤聯盟上的 LeaderPlayerId,無法在資料層強制領導者的 AllianceId 實際上是該聯盟。這只是對任何玩家的任意 FK。
我們不能使用 Player 上的 AllianceId 為領導者建立類似一對一的關系,因為該 FK 用于確定該玩家所屬的聯盟。
如果您不想在 Alliance 表中使用 LeaderPlayerId,則當前結構的另一種選擇是在播放器上使用“IsLeader”標志。這將與聯盟 ID 結合使用,以表明該玩家是其關聯聯盟的領導者。這意味著如果你有一個聯盟只能有一個領導者的規則,那么你需要在代碼中執行該規則并使用資料健康檢查來檢測是否以某種方式為聯盟分配了多個領導者。設定資料運行狀況檢查腳本也可以使用 LeaderPlayerId 方法來解決“領導者不屬于該聯盟”的情況。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/482770.html
