外部キー制約その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に追加的なコンフィギュレーションを突っ込むことで様々なコトが出来るようになります。
今回は、リレーションシップのコンフィグを入れ込んでいる形になります。順を追って説明すると

  1. BlandのEntityTypeConfigurationを取得する
  2. EntityTypeConfiguration.HasRequiredメソッドでナビゲーションプロパティを指定する
  3. RequiredNavigationPropertyが戻ってくるので、1:*となるようにRequiredNavigationProperty.WithManyを指定し、Manufacturer側のナビゲーションプロパティを指定する
  4. そうすることで、ForeignKeyNavigationPropertyConfigurationが戻るので、これをDBのフィールド”ManufacuturersId”にマップする。
  5. 最後に、戻ってきたCascadableNavigationPropertyConfigurationの、WillCascadeOnDeleteをtrue指定にすることで、Manufacturer側の要素が削除されたら、関連するBlandも一緒に削除するように定義する。

と言う流れになります。
属性を付けるより厄介な作業となりますが、逆にキメの細やかな制御がこれで可能になります。


また、次回以降のテーマとなりますが

  • 1:1の関係の構築
  • 1:0又は1の関係の構築

等も可能になります。