web-dev-qa-db-ja.com

Entity Framework 4.1のInverseProperty属性とForeignKey

外部キーを使用して、EmployeeエンティティとTeamエンティティの間に2つの参照を作成します。だから私は次のように2つのエンティティを定義しました

public class Employee
{
    public int EmployeeId { get; set; }
    public string Name { get; set; }

    [ForeignKey("FirstTeam")]
    public int FirstTeamId { get; set; }

    [InverseProperty("FirstEmployees")]
    public virtual Team FirstTeam { get; set; }

    [ForeignKey("SecondTeam")]
    public int SecondTeamId { get; set; }

    [InverseProperty("SecondEmployees")]
    public virtual Team SecondTeam { get; set; }
}

public class Team
{
    public int Id { get; set; }
    public string TeamName { get; set; }

    [InverseProperty("FirstTeam")]
    public virtual ICollection<Employee> FirstEmployees { get; set; }

    [InverseProperty("SecondTeam")]
    public virtual ICollection<Employee> SecondEmployees { get; set; }
}

理論的には正しいと思いましたが、以下のように例外が表示されます:

{"Introducing FOREIGN KEY constraint 'Employee_SecondTeam' on table 'Employees' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.\r\nCould not create constraint. See previous errors."}

誰かが私を助けてくれますか?

よろしくお願いします

31
Ray

理論的には正しいですが、SQLサーバー(エンティティフレームワークではありません)では、1人の従業員が第1チームと第2チームの両方のメンバーになることを許可しているため、これは望ましくありません。 Teamを削除すると、同じEmployeeエンティティへの複数の削除パスが発生します。

これは、外部キーを必須(null不可)として定義する場合、EFコードでデフォルトで最初に使用されるカスケード削除と一緒に使用できません。

例外を回避したい場合は、滑らかなマッピングを使用する必要があります。

public Context : DbContext
{
    public DbSet<Employee> Employees { get; set; }
    public DbSet<Team> Teams { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Employee>()
                    .HasRequired(e => e.SecondTeam)
                    .WithMany(t => t.SecondEmployees)
                    .HasForeignKey(e => e.FirstTeamId)
                    .WillCascadeOnDelete(false);

        ...
    }
}

これにより、チームを削除する前にSecondTeamのメンバーを手動で削除する必要があるシナリオになります。

54
Ladislav Mrnka

前の回答ではすべてが正しいですが、1つ間違っています

    modelBuilder.Entity<Employee>()
                .HasRequired(e => e.SecondTeam)
                .WithMany(t => t.SecondEmployees)
                .HasForeignKey(e => e.SecondTeamId) // mistake
                .WillCascadeOnDelete(false);

FirstTeamIdの代わりにSecondTeamIdを使用すると、SecondTeam navigationプロパティは常にFirstTeamになります

2