エラー

One to One, One to Many, Many to Manyリレーションシップの定義方法を紹介しました。
しかし、モデル間にどんどんリレーションシップを張っていくと次のようなエラーがマイグレーションで発生する場合があります。

Introducing FOREIGN KEY constraint 'FK_dbo.XXXXYYYY_dbo.YYYYs_YYYY_Id' on table 'XXXXYYYY' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.

今回はこのエラーを回避します。

リレーションシップ

さて、先のエラーですが、次ようなコードを書くとおこります。

[csharp]
public class Group
{
public string Id { get; set; }
public string Name { get; set; }
public string OrnerId { get; set; }
public virtual ApplicationUser Orner { get; set; }
public virtual ICollection<ApplicationUser> Members { get; set; }
public Group()
{
this.Id = Guid.NewGuid().ToString();
this.Members = new HashSet<ApplicationUser>();
}
}
public class ApplicationUser : IdentityUser
{
public virtual ICollection<Group> ManaginGroups { get; set; }
public virtual ICollection<Group> ParticipatingGroups { get; set; }
public ApplicationUser()
{
this.ManaginGroups = new HashSet<Group>();
this.ParticipatingGroups = new HashSet<Group>();
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder
.Entity<ApplicationUser>()
.HasMany<Group>(x => x.ParticipatingGroups)
.WithMany(x => x.Members)
.Map(x => x.ToTable("UserGroup"));
modelBuilder
.Entity<ApplicationUser>()
.HasMany<Group>(x => x.ManaginGroups)
.WithRequired(x => x.Orner);
base.OnModelCreating(modelBuilder);
}
}
[/csharp]

これは、ユーザが複数のグループを管理し、かつ複数のグループに参加することを記述したものです。ユーザと管理しているグループのリレーションシップがOne to Manyで、ユーザと参加グループはMany to Manyです。
この状態で、update-databaseを行うと、先のエラーが出力されます。

これは、ManaginGroupsとParticipatingGroupsのように複数の縦続(カスケード)があるためにおこります。また、別パターンとして最終的にリレーションが閉路を作ってしまった際にも生じます。

解決方法

これを解決するためには縦続を切る必要があります。そのためにWillCascadeOnDeleteメソッドを利用し、次のようにManagingGroupのリレーションを定義します。

[csharp]
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder
.Entity<ApplicationUser>()
.HasMany<Group>(x => x.ParticipatingGroups)
.WithMany(x => x.Members)
.Map(x => x.ToTable("UserGroup"));
modelBuilder
.Entity<ApplicationUser>()
.HasMany<Group>(x => x.ManaginGroups)
.WithRequired(x => x.Orner).WillCascadeOnDelete(false);
base.OnModelCreating(modelBuilder);
}
}
[/csharp]

これで、update-databaseを実行してもオコられません。やったね!

CATEGORIES