私は、同じテーブルへの2つの外部キー参照を持つことに問題があります。外部キーIDフィールドに値が設定されますが、ナビゲーションフィールドとリスト(チームフィールド)は表示されません。両方ともnullです。
私のクラスは:
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);
}
}
HomeTeamプロパティとAwayTeamプロパティに[ForeignKey()]
属性を追加しようとしましたが効果はありません。私はまた、他の方法で動作するように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が含まれていますが、Teamオブジェクトはまだ入力されていません。
誰かが私が間違っていることを考えている?これはまったく新しいプロジェクトであり、新しいデータベースであり、レガシーコードが干渉することはありません。私はEntity Framework CoreでVisual Studio 2017rcを使用しています。
現在、EFコアは遅延ロードをサポートしていません。トラッキングの問題はこちら
これは、デフォルトでナビゲーションプロパティがロードされず、nullのままであることを意味します。回避策として、積極的な読み込みパターンや明示的な読み込みパターンを使用することができます。
Eager Loading
熱心な読み込みは、 Include
APIを使用してクエリを実行している間に熱心に必要とされる参照データを要求するパターンです。使い方は、EF6での作業とは多少異なります。ナビゲーションをインクルードするには、クエリのincludeメソッドにラムダ式(または文字列名)を指定します。
例えば、 await _context.Fixtures.Include(f => f.HomeTeam).FirstOrDefaultAsync(f => f.Id == id);
現在のところ、フィルタ処理されたインクルードはサポートされていないため、ナビゲーションを完全にロードするか除外するかをリクエストできます。したがって、ラムダ式は複雑ではありません。単純なプロパティアクセスでなければなりません。また、ネストされたナビゲーションをロードするには、( abc
ような)プロパティアクセス呼び出しでチェーンするか、コレクション後のナビゲーション(連鎖できないため)でThenInclude
使用することができます。
例えば、 await _context.Fixtures.Include(f => f.HomeTeam).ThenInclude(t=> t.HomeFixtures).FirstOrDefaultAsync(f => f.Id == id);
pathのすべてのnaviagationsにデータを移入するために呼び出されるエンティティタイプからのナビゲーションのパスをインクルードすることを覚えておくとよいでしょう。 2番目以降のレベルで複数のナビゲーションを使用する場合は、繰り返し呼び出しを行う必要があります。これは構文のためだけであり、クエリは最適化され、繰り返しの作業は行われません。また、文字列を含めると、ThenIncludeを使用しなくても全体のナビゲーションパスを指定できます。参照ナビゲーションは結合を利用して単一の問合せで必要なすべてのデータをフェッチすることができるため、コレクションのナビゲーションはすべての関連データを単一の問合せでロードできます。
明示的な読み込み
オブジェクトをメモリにロードしてナビゲーションをロードする必要がある場合、ナビゲーションプロパティにアクセスしている間に遅延読み込みがロードされている間は、 Load
メソッドを自分で呼び出す必要があります。これらのメソッドは、 ReferenceEntry
またはCollectionEntry
定義されてい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
するためにEntityEntry
に関するReference
が必要です。コレクションのナビゲーションに相当するメソッドはCollection
です。次に、 Load
メソッドを呼び出して、ナビゲーションにデータをロードします。また、必要に応じてLoadAsync
非同期バージョンもあります。
お役に立てれば。