Entity Framework Code Firstにおいて複数のリレーションシップを追加する(Fluent API)

題名が長いですね。
Entity Frameworkで、Code Firstでデータベースを作成する際に、例えば次の図のようなリレーションシップを構成したいときどうするか、という話です。

テーブル間に複数のリレーション

1つのテーブルに複数のリレーション

これは、モデルクラスの定義だけではできません。多分。
ただ参照を作っただけでは、当然、どのプロパティがどのリレーションに対応するのかEntity Frameworkは認識できないので、エラーが出るかとんでもないリレーションが作成されます。
こういった、モデルクラスの定義だけで表現できないリレーションを構成するには、Fluent APIを用います。

ではFluent APIの説明をする前に、モデルクラスの定義だけで構築した場合のリレーションを見てみましょう。
クラス定義はこんな感じ。

public class Block
{
    public int Id { get; set; }

    public virtual Block Parent { get; set; }
    public virtual ICollection<Block> Children { get; set; }

    public virtual Block Next { get; set; }
    public virtual Block Previous { get; set; }
}

他のクラスも似たような感じなので省略します。
属性は全くつけていません。この定義でデータベースを構築すると…?

おかしくなっちゃったリレーション

なんということでしょう。ナビゲーションプロパティ毎にリレーションが作成されてしまいました。
新しいグループに所属したら、そのGroupのUsersにも勝手に追加されてほしいのに、これではそんなこと全然してくれないわけです。
ナビゲーションプロパティ、GroupsとUsers間には関係があるんだということを、Entity Frameworkに教える必要があります。

ではどう教えるか。Fluent APIを使います。
Fluent APIは、ContextクラスでOnModelCreatingメソッドをオーバーライドして記述します。
今回の場合どうすればよいのか見てみましょう。

class TestContext : DbContext
{
    static TestContext()
    {
        Database.SetInitializer(new DropCreateDatabaseAlways<TestContext>());
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>().HasMany(model => model.MyGroups).WithOptional(model => model.Owner);
        modelBuilder.Entity<User>().HasMany(model => model.Groups).WithMany(model => model.Users);

        modelBuilder.Entity<Block>().HasMany(model => model.Children).WithOptional(model => model.Parent);
        modelBuilder.Entity<Block>().HasOptional(model => model.Next).WithOptionalDependent(model => model.Previous);
    }

    public DbSet<User> Users { get; set; }
    public DbSet<Group> Groups { get; set; }

    public DbSet<Block> Blocks { get; set; }
}

これで、各リレーションが、意図通りに作成されます。

カテゴリー: プログラミング タグ: , , , , パーマリンク

Entity Framework Code Firstにおいて複数のリレーションシップを追加する(Fluent API) への2件のフィードバック

  1. Linux VPS のコメント:

    I keep hearing about the Entity Framework fluent-api but I am struggling to find a good reference on this. What is it?

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です