Mog*_*og0 5 c# entity-framework entity-framework-core
我在对同一个表有两个外键引用时遇到问题。外键 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; }
}
Run Code Online (Sandbox Code Playgroud)
和我的 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);
}
}
Run Code Online (Sandbox Code Playgroud)
我曾尝试向[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);
Run Code Online (Sandbox Code Playgroud)
和客场固定装置相同,但这会产生相同的行为。
我如何查询似乎并不重要,但最简单的情况是
Fixture fixture = await _context.Fixtures.SingleOrDefaultAsync(f => f.Id == id);
Run Code Online (Sandbox Code Playgroud)
返回的夹具对象包含有效且在数据库中的团队 ID,但团队对象仍未填充。
有谁知道我做错了什么?这是一个全新的项目和全新的数据库,因此没有遗留代码的干扰。我将 Visual Studio 2017rc 与 Entity Framework Core 一起使用。
目前EF Core不支持延迟加载。跟踪问题在这里
这意味着默认情况下导航属性不会被加载并保持为空。作为解决方法,您可以使用预先加载或显式加载模式。
急切加载
预加载是一种模式,您在使用IncludeAPI 运行查询时急切地请求所需的引用数据。其用法与 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);
最好记住,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();
Run Code Online (Sandbox Code Playgroud)
对于参考导航,您需要Reference获取EntityEntryReferenceEntry。对于集合导航,等效方法是Collection. 然后你只需调用Load它的方法来加载导航中的数据。如果您需要的话,还有异步版本LoadAsync。
希望这可以帮助。
| 归档时间: |
|
| 查看次数: |
3656 次 |
| 最近记录: |