2017年2月10日金曜日

Entity Framework 多対多

コンソールアプリケーションで試します。
基本的なことはこちら→ConsoleApplicationでCodeFirst

多対多です。
ブログの記事にタグがぶら下がる状態がまさにそれですね。
イメージしやすいのでこれを題材にいろいろ掘り下げてみます。





記事のテーブル。
名前と本文だけのシンプルな構成

model/Article.cs
using System.Collections.Generic;

namespace EntityFramework.model
{
    class Article
    {
        public int ID { get; set; }
        public string Title { get; set; }
        public string Body { get; set; }

        //リレーション(相手側が多なのでCollection)
        public virtual ICollection Tag { get; set; }
    }
}


タグのテーブル

model/Tag.cs
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace EntityFramework.model
{
    class Tag
    {
        public int ID { get; set; }
        [Required]
        [Index(IsUnique=true)]
        [MaxLength(50)]
        public string Name { get; set; }

        //リレーション(相手側が多なのでCollection)
        public virtual ICollection
Article { get; set; } } }

tagはユニークにしたいので Index(IsUnique=true)をつけています。
ユニーク制約をつけるためには、文字数が最大になっていたらつかないので文字数制限をつけます

プレーンなクラスとDBをつなぐクラス
model/BlogContext.cs
using System.Data.Entity;

namespace EntityFramework.model
{
    class BlogContext : DbContext
    {
        public DbSet
Articles { get; set; } public DbSet Tags { get; set; } } }

Add-Migrationして Update-Databaseしてテーブルを作成します。
※こまかいとこはすっとばします。



多対多なので自動的に中間テーブル(TagArticles)が作られています。


データを格納してみます。

Program.cs
using EntityFramework.model;
using System.Collections.Generic;

namespace EntityFramework
{
    class Program
    {
        static void Main(string[] args)
        {
            BlogContext db = new BlogContext();

            // Article側にTagをぶら下げる
            Article article = new Article { Body = "Body_A", Title = "Title_A" };
            Tag tag1 = new Tag { Name = "C#" };
            Tag tag2 = new Tag { Name = "SQL Server" };
            article.Tag = new List { tag1, tag2 };
            db.Articles.Add(articleA);
            db.SaveChanges(); // 登録
        }
    }
}

記事Aに C#とSQL Serverを登録しています。
タグはUniqueキー制約をつけているのでこんな登録の仕方したらだめなわけですが
サンプルということもあって、初回登録で空なのでこんな書き方しています。




記事Bを追加します。
今回は、タグがすでにあることを想定して事前に取得して、なければタグのインスタンスを生成するようにしています。
??演算子で nullだったら後ろの処理をするようにしています。

Program.cs
using EntityFramework.model;
using System.Collections.Generic;
using System.Linq;

namespace EntityFramework
{
    class Program
    {
        static void Main(string[] args)
        {
            BlogContext db = new BlogContext();

            // Article側にTagをぶら下げる
            Article article = new Article { Body = "Body_B", Title = "Title_B" };

            Tag tag1 = db.Tags.Where(t => t.Name == "C#").FirstOrDefault();
            tag1 = tag1 ?? new Tag { Name = "C#" };

            Tag tag2 = db.Tags.Where(t => t.Name == "SQL Server").FirstOrDefault();
            tag2 = tag2 ?? new Tag { Name = "SQL Server" };

            Tag tag3 = db.Tags.Where(t => t.Name == "ASP.NET").FirstOrDefault();
            tag3 = tag3 ?? new Tag { Name = "ASP.NET" };

            article.Tag = new List { tag1, tag2, tag3 };
            db.Articles.Add(article);
            db.SaveChanges(); // 登録
        }
    }
}



Program.cs
using EntityFramework.model;
using System.Collections.Generic;
using System.Linq;

namespace EntityFramework
{
    class Program
    {
        static void Main(string[] args)
        {
            BlogContext db = new BlogContext();

            // Article側にTagをぶら下げる
            Article article = new Article { Body = "Body_C", Title = "Title_C" };

            Tag tag1 = db.Tags.Where(t => t.Name == "C#").FirstOrDefault();
            tag1 = tag1 ?? new Tag { Name = "C#" };

            Tag tag2 = db.Tags.Where(t => t.Name == "ASP.NET").FirstOrDefault();
            tag2 = tag2 ?? new Tag { Name = "ASP.NET" };

            article.Tag = new List { tag1, tag2 };
            db.Articles.Add(article);
            db.SaveChanges(); // 登録
        }
    }
}


0 件のコメント:

コメントを投稿