単体のテーブルの定義ではなく、テーブル間のリレーションの定義の仕方です。これもOnModelCreatingで指定します。例えば以下のような感じのクラスがあったとして
publicclass Person { publicint Id { get; set; } publicstring Name { get; set; } publicint Age { get; set; } public List<Address> Addresses { get; set; } } publicclass Address { publicint Id { get; set; } publicstring Country { get; set; } publicstring City { get; set; } publicint PersonId { get; set; } public Person Person { get; set; } }
このクラス間の関連を定義するには以下のようになります。Person側でHasManyってやってもいいけど、Address側だけで定義するだけでも動いてます。
protectedoverridevoid OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Person>() .ToTable("People") .Property(x => x.Name) .HasMaxLength(512) .IsRequired(); var address = modelBuilder.Entity<Address>(); address.ToTable("Addresses"); address.Property(x => x.City) .IsRequired(); // 多対1 address.HasOne(x => x.Person) // 反対側はMany .WithMany(x => x.Addresses) // 外部キーを指定 .HasForeignKey(x => x.PersonId) // 削除時の動作を指定 .OnDelete(Microsoft.Data.Entity.Metadata.DeleteBehavior.Restrict); }
リレーションのあるデータの投入は以下のように、データを素直に突っ込んでContextに渡してSaveChangesでOKです。
using (var ctx = new SampleContext()) { ctx.People.Add(new Person { Name = "Tanaka", Addresses = new List<Address> { new Address { City = "Tokyo" }, new Address { City = "Saitama" }, } }); ctx.SaveChanges(); }
データを取り出すときはInclude拡張メソッドを使って明示的に一緒に読み込むことを指定します。
// 以下のusingが必要// using Microsoft.Data.Entity;using (var ctx = new SampleContext()) { var p = ctx.People.Include(x => x.Addresses).First(); Debug.WriteLine(p.Name); foreach (var item in p.Addresses) { Debug.WriteLine(item.City); } } Debug.WriteLine("---"); using (var ctx = new SampleContext()) { var addresses = ctx.Addresses.Include(x => x.Person).ToArray(); foreach (var a in addresses) { Debug.WriteLine($"{a.City} {a.Person.Name}"); } }
余談
OneToManyがよく使うと思うのでそれだけ紹介してますが、OneToOneもばっちりあります。似たような感じで使えるので迷うことはないと思います。
後、ManyToManyはサポートされてないので関連表みたいなのに対応するクラスを自分で作って、それとOneToManyで繋ぎ合わせることでやらないといけません。要は、Entity Framework 6が裏でやってくれてたことを自分でやれと。将来的にはサポートされるのかな?