外部キー制約その2
てーことで、前回id:NetSeed:20110421はForeignKeyAttributeを使って、リレーションシップの作成をしてみました。
で、今回は、これをちょいと手直ししていきたいと思います。
前回の問題点
前回の方法では、若干冗長な"ManufacturerId"がプロパティとして定義されている必要がありました。しかし、本来このプロパティとナビゲーションプロパティのManufacturerは同じEntityを示すことになりますから、ManufacturerIdプロパティをどーにかして排除できないか?と言うのが今回のお題となります。
まずは属性とプロパティをなくしてしまう
この作業の手始めに、Blandクラスを以下のように若干手直しします。
public class Bland { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } public virtual Manufacturer Manufacturer { get; set; } [Required] public string Name { get; set; } }
前回との違いは、
- ManufacutersIdプロパティを除去した
- ForeignKeyAttributeの除去
となります。
当然、この状態で動かしてしまうと、ManufacutereとBland間のリレーションが存在しなくなってしまいますから、何とかしなけりゃまずいわけです。
SampleContextをいじる
で、次にすべきは、属性でリレーションを定義する代わりに、別の方法で定義する方法となります。これは、DbContextクラスを継承したSampleContextクラスの中で行う作業となります。
具体的には、OnModelCreatingメソッドをオーバーライドすることになります。
で、書き換えたSampleContextクラスは以下の通りです。
public class SampleContext : DbContext { public SampleContext(string con) : base(con) { } public DbSet<Manufacturer> Manufacturers { get; set; } public DbSet<Bland> Blands { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<Bland>() .HasRequired(x => x.Manufacturer) .WithMany(x => x.Blands) .Map(x => x.MapKey("ManufacturersId")); .WillCascadeOnDelete(true); base.OnModelCreating(modelBuilder); } }
OnModelCreatingが何を実際やっているかというと、名前通り、Code-FirstからDBを定義する前に、呼ばれるメソッドとなり、引数で受け取ったDbModelBuilderに追加的なコンフィギュレーションを突っ込むことで様々なコトが出来るようになります。
今回は、リレーションシップのコンフィグを入れ込んでいる形になります。順を追って説明すると
- BlandのEntityTypeConfigurationを取得する
- EntityTypeConfiguration.HasRequiredメソッドでナビゲーションプロパティを指定する
- RequiredNavigationPropertyが戻ってくるので、1:*となるようにRequiredNavigationProperty.WithManyを指定し、Manufacturer側のナビゲーションプロパティを指定する
- そうすることで、ForeignKeyNavigationPropertyConfigurationが戻るので、これをDBのフィールド”ManufacuturersId”にマップする。
- 最後に、戻ってきたCascadableNavigationPropertyConfigurationの、WillCascadeOnDeleteをtrue指定にすることで、Manufacturer側の要素が削除されたら、関連するBlandも一緒に削除するように定義する。
と言う流れになります。
属性を付けるより厄介な作業となりますが、逆にキメの細やかな制御がこれで可能になります。
また、次回以降のテーマとなりますが
- 1:1の関係の構築
- 1:0又は1の関係の構築
等も可能になります。