繁体   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