2017-02-16 60 views
2

我有兩個外鍵引用到同一個表的問題。 外鍵id字段被填充,但導航字段和列表(Team字段)不是 - 它們都是空的。實體框架核心兩個外鍵 - 相同表

我的類別是:

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); 

返回固定對象包含團隊的ID是有效的,並在數據庫中,但仍沒有填充的團隊對象。

有沒有人知道我在做什麼錯? 這是一個全新的項目和全新的數據庫,因此不存在傳統代碼干擾。 我使用Visual Studio 2017rc與實體框架核心。

+0

數據存在於數據庫中?顯示查詢。 –

+0

@SteveGreene我已經添加了一個示例查詢的問題,但它發生在多個查詢。在Fixture對象中返回的TeamIds是有效的並且與數據庫中的Team記錄匹配。 – Mog0

+2

EF內核中還不支持延遲加載請參閱https://github.com/aspnet/EntityFramework/issues/3797 您需要在導航上進行急切加載以使其填充。 Doc鏈接:https://docs.microsoft.com/en-us/ef/core/querying/related-data – Smit

回答

1

目前EF Core不支持延遲加載。跟蹤問題here

這意味着默認情況下導航屬性將不會被加載,並將保持爲空。作爲解決方法,您可以使用急切加載或顯式加載模式。

預先加載

預先加載是你的,你需要急切地同時使用Include API運行查詢所引用的數據請求模式。這個用法與EF6中的工作方式有所不同。要包含任何導航,可以在查詢中的include方法中指定lambda表達式(或字符串名稱)。

例如await _context.Fixtures.Include(f => f.HomeTeam).FirstOrDefaultAsync(f => f.Id == id);

目前,過濾包括不支持,因此您可以請求完全加載導航或排除它。所以lambda表達式不能很複雜。它必須是簡單的財產訪問。此外,要加載嵌套導航,您可以將其鏈接到屬性訪問調用(如a.b.c),或者在收集導航後(因爲您無法鏈接它們)使用ThenInclude

例如await _context.Fixtures.Include(f => f.HomeTeam).ThenInclude(t=> t.HomeFixtures).FirstOrDefaultAsync(f => f.Id == id);

這將是一件很好的事情,包括代表從被調用的實體類型導航的路徑,以填充路徑上的所有naviagations。如果您在第二級或更高級別包括多個導航,通常您可能需要重複撥打電話。這只是爲了語法,而查詢將被優化,不會重複工作。同樣對於字符串包含,您可以指定完整的導航路徑而無需使用ThenInclude。由於參考導航可以利用連接獲取單個查詢中需要的所有數據,因此集合導航可以在單個查詢中加載所有相關數據,提前加載是​​性能最高的方式。

顯式加載

當您在加載到內存中的對象和需要裝載的導航,而延遲加載會加載它,而訪問導航屬性,如果沒有,你需要調用Load方法由你自己。這些方法在ReferenceEntryCollectionEntry上定義。

例如

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(); 

僅供參考導航則需要ReferenceEntityEntry得到ReferenceEntry。對於收集導航的等效方法是Collection。然後您只需調用Load方法即可在導航中加載數據。如果需要,還有LoadAsync的異步版本。

希望這會有所幫助。