このエラーに関する様々な文脈では数多くの質問がありますが、これまで私は自分の状況に当てはまるものを見つけることができませんでした。
私は第3のテーブルと確立しようとしている多面的な関係を持っています。それは基本的に、協会の管理者です。すべてのマネージャーは人ですが、すべての人がマネージャーではなく、すべての人に多数のマネージャーがあり、すべてのマネージャーには多くの人がいます。だからマネージャーのテーブルにはPersonIdsがあります。編集中の人事管理者には、人をマネージャーに関連付けるオプションがあります。使用可能なマネージャーをクリックして[保存]をクリックすると、エラーが表示されます。
INSERTステートメントがFOREIGN KEY制約 "FK_dbo.ManagerToEngineer_dbo.Manager_ManagerId"と競合しました。競合はデータベース "PROJECTNAME_16ce3f6a2a6c4ff0b1ce147d126984ba"、テーブル "dbo.Manager"、列 'ManagerId'で発生しました。ステートメントは終了されました。
SaveChangesメソッドでこのエラーが発生します。
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(PersonViewModel person)
{
if (ModelState.IsValid)
{
//var MyPerson = db.people.Find(person.PersonId);
//MyPerson.FirstName = person.FirstName;
//MyPerson.LastName = person.LastName;
foreach (var item in db.ManagersToEngineers)
{
if (item.EngineerId == person.PersonId)
{
db.Entry(item).State = EntityState.Deleted;
}
}
foreach (var item in person.EngineerManagers)
{
if (item.Checked)
{
db.ManagersToEngineers.Add(new ManagerToEngineer() { EngineerId = person.PersonId, ManagerId = item.Id });
}
}
//db.Entry(person).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(person);
}
関連するモデル:
public class ManagerToEngineer
{
[Key]
public int ManagerToEngineerId { get; set; }
[Required]
[ForeignKey("engineer")]
public int EngineerId { get; set; }
[Required]
[ForeignKey("manager")]
public int ManagerId { get; set; }
public virtual Person engineer { get; set; }
public virtual Manager manager { get; set; }
}
public class Manager
{
[Key]
public int ManagerId { get; set; }
[Required]
[ForeignKey("person")]
public int EngineerId { get; set; }
public virtual Person person { get; set; }
public ICollection<ManagerToEngineer> ManagersToEngineers { get; set; }
}
public class PersonViewModel
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[Display(Name = "Managers")]
public List<CheckBoxViewModel> EngineerManagers { get; set; }
}
public class CheckBoxViewModel
{
public int Id { get; set; }
public string FullName { get; set; }
public bool Checked { get; set; }
}
まず、モデルを再考する必要があります。フレーズ:
すべてのマネージャは人ですが、すべての人がマネージャではありません
多対多の関係に変換されません。学生には多くのコースがあり、コースには多くの学生がいます。多対多の関係です。あなたの状況はより翻訳されました。すべてのマネージャーは、オブジェクトの構成ではなく継承を暗示する人物です。しかし、学習のためにあなたの例を考えてみましょう。
次のコード(私はちょっとした名前を変更しましたが、混乱を招くので、EngineerとPersonを同じ意味で使用しないでください):
public class Person
{
public Person()
{
Managers = new HashSet<Manager>();
}
[Key]
public int PersonId { get; set; }
public string Name { get; set; }
public virtual ICollection<Manager> Managers { get; set; }
}
public class Manager
{
public Manager()
{
Persons = new HashSet<Person>();
}
[Key]
public int ManagerId { get; set; }
public virtual ICollection<Person> Persons { get; set; }
}
public class CompanyContext : DbContext
{
public DbSet<Person> Persons { get; set; }
public DbSet<Manager> Managers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasMany(p => p.Managers).WithMany(m => m.Persons)
.Map(t => t.MapLeftKey("PersonID")
.MapRightKey("ManagerID")
.ToTable("PersonToManager"));
}
}
挿入を実行するときに、これが良いデザインではない理由がわかります:
static void Main(string[] args)
{
using (var db = new CompanyContext())
{
// add a person
var person = new Person() { Name = "Joe" };
db.Persons.Add(person);
// "make" him manager
var manager = new Manager();
manager.Persons.Add(person);
db.Managers.Add(manager);
db.SaveChanges();
}
Console.ReadKey();
}
上記のコードはコンパイルして実行する必要があります(ただし、SqlLocalDbの問題があるためテストできませんでした)。アソシエーションテーブルのクラスを明示的に作成する必要はないことに注意してください。Entity Frameworkは、 modelBuilderが正しい定義を持っていることを条件として、それ自体を推論することができます。
上記のコードは多対多の関係の一例にすぎず、実際には良いデータベース設計ではありませんが、コードと私の違いを見るためのリンクを提供するのではなく、投稿しました。チュートリアルに従ってくださいここを SQLでの継承関係を設計するなど方法(データベース設計は、コードに変換する方法にはいくつかのチュートリアルを読んでくださいより良く理解するために、これはプロジェクトが(いくつかの点で)するためのものであるかの学習運動以上のもの)。