簡體   English   中英

實體框架核心兩個外鍵 - 相同的表

[英]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方法。 這些方法在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異步版本。

希望這可以幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM