[英]Entity Framework Core Two Foreign Keys - Same Table
我遇到了對同一個表有兩個外鍵引用的問題。 填充了外鍵id字段,但導航字段和列表(團隊字段)不是 - 它們都是空的。
我的課程是:
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Fixture> HomeFixtures { get; set; }
public virtual ICollection<Fixture> AwayFixtures { get; set; }
}
public class Fixture
{
public int Id { get; set; }
public int HomeTeamId { get; set; }
public int AwayTeamId { get; set; }
public Team HomeTeam { get; set; }
public Team AwayTeam { get; set; }
}
和我的dbContext
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public DbSet<Team> Teams { get; set; }
public DbSet<Fixture> Fixtures { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Fixture>()
.HasOne(f => f.HomeTeam)
.WithMany(t => t.HomeFixtures)
.HasForeignKey(t => t.HomeTeamId)
.OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.Restrict);
modelBuilder.Entity<Fixture>()
.HasOne(f => f.AwayTeam)
.WithMany(t => t.AwayFixtures)
.HasForeignKey(t => t.AwayTeamId)
.OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.Restrict);
}
}
我嘗試將[ForeignKey()]
屬性添加到HomeTeam和AwayTeam屬性,但它沒有任何效果。 我也試過改變OnModelCreating方法以另一種方式工作,即
modelBuilder.Entity<Team>()
.HasMany(t => t.HomeFixtures)
.WithOne(f => f.HomeTeam)
.HasForeignKey(f => f.HomeTeamId)
.OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.Restrict);
對於遠程固定裝置也是如此,但這會產生相同的行為。
我的查詢方式似乎並不重要,但最簡單的情況是
Fixture fixture = await _context.Fixtures.SingleOrDefaultAsync(f => f.Id == id);
返回的fixture對象包含有效且在數據庫中但仍未填充Team對象的團隊ID。
有誰知道我做錯了什么? 這是一個全新的項目和一個全新的數據庫,因此沒有遺留代碼干擾。 我正在使用Visual Studio 2017rc和Entity Framework Core。
目前EF Core不支持延遲加載。 跟蹤問題在這里
這意味着默認情況下,導航屬性不會被加載並保持為null。 作為解決方法,您可以使用預先加載或顯式加載模式。
渴望加載
Eager loading是一種模式,您可以在使用Include
API運行查詢時急切地請求引用的數據。 其用法與EF6中的工作方式略有不同。 要包含任何導航,請在查詢中的include方法中指定lambda表達式(或字符串名稱)。
例如await _context.Fixtures.Include(f => f.HomeTeam).FirstOrDefaultAsync(f => f.Id == id);
目前,不支持過濾包含,因此您可以請求完全加載導航或排除導航。 所以lambda表達式不能復雜。 它必須是簡單的屬性訪問。 另外,要加載嵌套導航,您可以使用屬性訪問調用(如abc
)鏈接它們,或者在其后集合導航(因為您無法鏈接它們)時使用ThenInclude
。
例如await _context.Fixtures.Include(f => f.HomeTeam).ThenInclude(t=> t.HomeFixtures).FirstOrDefaultAsync(f => f.Id == id);
值得記住的是,include表示從被調用的實體類型導航的路徑,以填充路徑上的所有naviagations。 如果您在第二級或更高級別包含多個導航,通常可能需要編寫重復的呼叫。 這僅僅是為了語法,查詢將被優化,不會重復工作。 此外,使用字符串include,您可以指定整個導航路徑,而無需使用ThenInclude。 由於參考導航可以利用連接來獲取單個查詢中所需的所有數據,因此收集導航可以在單個查詢中加載所有相關數據,急切加載是最高效的方式。
明確加載
當您在內存中加載對象並需要加載導航時,延遲加載會在訪問導航屬性時加載它,如果沒有,您需要自己調用Load
方法。 這些方法在ReferenceEntry
或CollectionEntry
上定義。
例如
Fixture fixture = await _context.Fixtures.SingleOrDefaultAsync(f => f.Id == id);
_context.Entry(fixture).Reference(f => f.HomeTeam).Load();
var team = await _context.Teams.SingleOrDefaultAsync(t => t.Id == id);
_context.Entry(team).Collection(f => f.HomeFixtures).Load();
對於參考導航則需要Reference
上EntityEntry
得到ReferenceEntry。 對於集合導航,等效方法是Collection
。 然后,您只需在其上調用Load
方法即可在導航中加載數據。 如果需要, LoadAsync
異步版本。
希望這可以幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.