インクリメンタルなカイハツにっき

.NET 開発手法を中心に、これから始める方の一助となる記事を載せていく予定です。

実践 Entity Framework ~ ナビゲーションプロパティ

前回は、コードファーストを利用した、外部キーの設定方法について紹介しました。

外部キーの設定の時に利用した、ナビゲーションプロパティとはなんなんでしょう?
次のふたつのクラス(テーブル)に的を絞って考えます。

リレーションシップ

LINQ to SQL

繰り返しになりますが、地方自治体を表す Municipality クラスと、都道府県を表す Prefecture クラスです。

public class Municipality
{
    [Key]
    public string Code { get; set; }
    
    // 外部キー
    public string PrefectureCode { get; set; }

    // ナビゲーションプロパティ
    public Prefecture Prefecture { get; set; }
}

public class Prefecture
{
    [Key]
    public string Code { get; set; }

    public string Name { get; set; }
}
// 不要部分は省略

そしてコンテキストクラスです。

public class AddressDataContext : System.Data.Entity.DbContext
{
    public DbSet<Prefecture> Prefectures { get; set; }

    public DbSet<Municipality> Municipalities { get; set; }
}

マイグレーション適用済みでテーブルは既に作成されている状態とします。

例えば、自治体コード 13101(東京都千代田区)を取得したい場合は、次のようになります。

using(var context = new AddressDataContext())
{
    var entity = context.Municipalities.Where(q => q.Code == "13101").FirstOrDefault();
}

わかる方には当然のコードかと思います。
LINQラムダ式?という方...検索するか、まぁそうなるんだと、とりあえず思っておいてください。
LINQは奥が深いので、今後記事にする予定です。

Municipalities と Prefectures の間には、リレーションシップが設定されています。
では、自治体コード 13101 の 都道府県情報を取得したい場合、どうなるでしょうか?
ナビゲーションプロパティが無い状態だと...

using (var context = new AddressDataContext())
{
    var entity = context.Municipalities
        .Where(m => m.Code == "13101")
        .Join(context.Prefectures, m => m.PrefectureCode, p => p.Code, (m, p) => p)
        .FirstOrDefault();
}

これでなくても良いかもしれませんが、Join メソッドを利用し、ちょっとわかり辛くなっちゃいますね。
で、ナビゲーションプロパティを利用すると...

using (var context = new AddressDataContext())
{
    var entity = context.Municipalities
        .Where(m => m.Code == "13101")
        .Select(m => m.Prefecture).FirstOrDefault();
}

少しスッキリしました。

1から多を参照

ところで、当然逆もあるかと思います。
「東京都」に含まれている、自治体を取得したいという場合、通常ならば...

using (var context = new AddressDataContext())
{
    var list = context.Prefectures
        .Where(p => p.Name == "東京都")
        .Join(context.Municipalities, p => p.Code, m => m.PrefectureCode, (p, m) => m)
        .ToList();
}

これにも、当然ナビゲーションプロパティがあります。
今度は Prefecture クラスに、次を追加します。

public ICollection<Prefecture> Municipalities { get; set; }

1から多を参照するわけですから、型がコレクションになります。また参照側クラス型を指定する必要があります。
ICollection(T)インターフェースとしていますが、このインターフェースをもつ、IList(T) だったり、実クラスの List(T) であっても問題ありません。

そうすれば...

using (var context = new AddressDataContext())
{
    var list = context.Prefectures.Where(p => p.Name == "東京都")
        .SelectMany(p => p.Municipalities)
        .ToList();
}

これで、全く同じ動作になります。

ナビゲーションプロパティで外部キーを設定

このふたつのナビゲーションプロパティのうち、どちらかひとつが指定されている場合、外部キーが自動設定されます。
また、プロパティ名は実テーブルには影響を与えないので、何でも構いません。変更しても Add-Migration する必要もありません。

そんな感じで、非常にざっくりとではありますが、ナビゲーションプロパティの働きと使用方法を紹介しました。

外部キーの設定に関しては、この内容だけでは対応できない場合もあるでしょう。
そもそも外部キーなんか必要ない、リレーションだけ組めれば、的な要件もあるかと思います。

そんなときの対応は...次回以降で見ていきましょう。