準備

初めに、プロジェクトを用意します。ASP.NET WebアプリケーションでMVCテンプレートを選択します。

プロジェクトができたら、マイグレーションを有効化しておきます。

パッケージマネージャーコンソールで次のコマンドを実行します。

PM> Enable-Migrations -EnableAutomaticMigration

モデルクラス

今回はMany to Manyリレーションシップの例としてよく取り上げられる、著者と本の関係を実装してみます。共著のことを考慮するとまさに、Many to Manyの関係ですね。

ModelsフォルダにAuthor.cs、Book.csファイルを作成します。

Authorクラス、Bookクラスをそれぞれ次のように実装します。

[csharp]
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Web;
namespace ManyToManySample.Models
{
public class Author
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Book> Books { get; set; }
public Author()
{
this.Books = new HashSet&lt;Book&gt;();
}
}
}
[/csharp]

[csharp]
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Web;
namespace ManyToManySample.Models
{
public class Book
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<Author> Authors { get; set; }
public Book()
{
this.Authors = new HashSet<Author>();
}
}
}
[/csharp]

IdentityModels.csのApplicationDbContextクラスにエンティティコレクションを追加します。

[csharp]
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
public DbSet<Book> Books { get; set; }
public DbSet<Author> Authors { get; set; }
}
[/csharp]

リレーションシップ

次に、IdentityModels.csファイルのApplicationDbContextクラスのvoid OnModelCreating(DbModelBuilder modelBuilder)をオーバーライドし、エンティティの関連を定義します。

[csharp]
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
public DbSet<Book> Books { get; set; }
public DbSet<Author> Authors { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder
.Entity<Book>()
.HasMany<Author>(x => x.Authors)
.WithMany(x => x.Books)
.Map(x => x.ToTable("BookAuthor"));
base.OnModelCreating(modelBuilder);
}
}
[/csharp]

初期データ

登録フォームを作ると長くなるので、データはSeedで用意します。

[csharp]
namespace ManyToManySample.Migrations
{
using System;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;
using ManyToManySample.Models;
internal sealed class Configuration : DbMigrationsConfiguration<ManyToManySample.Models.ApplicationDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
}
protected override void Seed(ManyToManySample.Models.ApplicationDbContext context)
{
Author authorA = new Author { Name = "A" }
, authorB = new Author { Name = "B" }
, authorC = new Author { Name = "C" };
Book hoge = new Book { Title = "Hoge" }
, fuga = new Book { Title = "Fuga" }
, piyo = new Book { Title = "piyo" };
authorA.Books.Add(hoge);
hoge.Authors.Add(authorA);
authorA.Books.Add(piyo);
piyo.Authors.Add(authorA);
authorB.Books.Add(hoge);
hoge.Authors.Add(authorB);
authorB.Books.Add(fuga);
fuga.Authors.Add(authorB);
authorC.Books.Add(fuga);
fuga.Authors.Add(authorC);
authorC.Books.Add(piyo);
piyo.Authors.Add(authorC);
context.Authors
.AddOrUpdate(x => x.Name, authorA, authorB, authorC);
context.Books
.AddOrUpdate(x => x.Title, hoge, fuga, piyo);
}
}
}
[/csharp]

3人の著者、A、B、Cがそれぞれ、hogeとpiyo、hogeとfuga、fugaとpiyoという本を書いている関係性になっています。

コントローラの作成

コントローラを自動生成します。(自動生成の方法

AuthorsControllerBooksControllerとそれぞれに付随するViewを作成します。

また、それぞれのDetail.cshtmlを次のように編集します。

Authors/Details.cshtml

[html]
@model ManyToManySample.Models.Author
@{
ViewBag.Title = "Details";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Details</h2>
<div>
<h4>Author</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.Name)
</dt>
<dd>
@Html.DisplayFor(model => model.Name)
</dd>
</dl>
<ul class="list-group">
@foreach (var book in Model.Books)
{
<li class="list-group-item">@book.Title</li>
}
</ul>
</div>
<p>
@Html.ActionLink("Edit", "Edit", new { id = Model.Id }) |
@Html.ActionLink("Back to List", "Index")
</p>
[/html]

Books/Details.cshtml

[html]
@model ManyToManySample.Models.Book
@{
ViewBag.Title = "Details";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Details</h2>
<div>
<h4>Book</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.Title)
</dt>
<dd>
@Html.DisplayFor(model => model.Title)
</dd>
</dl>
<ul class="list-group">
@foreach(var author in Model.Authors)
{
<li class="list-group-item">@author.Name</li>
}
</ul>
</div>
<p>
@Html.ActionLink("Edit", "Edit", new { id = Model.Id }) |
@Html.ActionLink("Back to List", "Index")
</p>
[/html]

これで、必要なものはそろいました。

チェック

起動して、確かめてみます。

html://localhost:xxxxx/AuthorsからA、B、CいずれかのDetailsに飛びます。
html://localhost:xxxxx/BooksからHoge、Fuga、PiyoのいずれかのDetailsに飛びます。

many2many

まとめ

これで、One to OneOne to Many、Many to Manyの代表的なリレーションシップをマスターしました!
これら3つのリレーションシップがあれば、大体の構造は構築可能だと思います。

CATEGORIES