C# ASP.NET MVC级联删除

C# ASP.NET MVC级联删除,c#,entity-framework,asp.net-mvc-5,C#,Entity Framework,Asp.net Mvc 5,我有两个模型。 城镇: 使用命令更新数据库后,出现下一个错误: 在表“TownDistricts”上引入外键约束“FK_dbo.TownDistricts_dbo.Districts_District_ID”可能会导致循环或多个级联路径。指定“在删除时不执行操作”或“在更新时不执行操作”,或修改其他外键约束 我看到了这个链接: 引用解决方案: protected override void OnModelCreating(DbModelBuilder modelBuilder)

我有两个模型。 城镇:

使用命令更新数据库后,出现下一个错误:

在表“TownDistricts”上引入外键约束“FK_dbo.TownDistricts_dbo.Districts_District_ID”可能会导致循环或多个级联路径。指定“在删除时不执行操作”或“在更新时不执行操作”,或修改其他外键约束

我看到了这个链接: 引用解决方案:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Town>().HasRequired(t => t.Districts).WithMany().WillCascadeOnDelete(false);
            modelBuilder.Entity<District>().HasRequired(d => d.Towns).WithMany().WillCascadeOnDelete(false);
        }
您必须至少在一个实体中使阶段成为可选的(即从阶段属性中删除[Required]属性)

但我没有[必需]属性。 我还尝试了这个解决方案:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Town>().HasRequired(t => t.Districts).WithMany().WillCascadeOnDelete(false);
            modelBuilder.Entity<District>().HasRequired(d => d.Towns).WithMany().WillCascadeOnDelete(false);
        }
但我找不到开发人员是如何在模型或其他方面解决这个问题的

谢谢你的帮助

根据需要,您不需要显式外键声明
public int?TownID{get;set;}
在class
District
中,反之亦然(在另一个类中)。实体框架似乎能够配置所有必要的连接(数据库中的附加表),只需使用声明的导航集合,如
publicvirtualicollection{get;set;}

添加。当声明两个单一属性
public int时,您的意思是什么?DistrictID{get;set;}
和集合
公共虚拟ICollection Districts{get;set;}
。您是否混淆了EF中多对多关系的概念,或者您的意思是这些属性表示不同的东西?如果它们表示不同的内容,那么您应该使用fluentapi来正确配置它们

更新。OP澄清后,我建议使用以下代码

public class TestEfContext : ApplicationDbContext {
    public DbSet<Town> Towns { get; set; }
    public DbSet<District> Districts { get; set; }

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

        modelBuilder.Entity<Town>()
            .HasMany<District>(x => x.Districts)
            .WithOptional(x => x.Town);

        modelBuilder.Entity<District>()
            .HasMany<Town>(x => x.Towns)
            .WithOptional(x => x.District);
    }
}

public class Town {
    [Key]
    public int Id { get; set; }

    public District District { get; set; }

    public virtual ICollection<District> Districts { get; set; }

    public override string ToString() {
        return Id.ToString();
    }
}

public class District {
    [Key]
    public int Id { get; set; }

    public Town Town { get; set; }

    public virtual ICollection<Town> Towns { get; set; }

    public override string ToString() {
        return Id.ToString();
    }
}

这意味着Town1将有District=District1和empty Districts集合,而District1将有Town=null和Towns集合,其中有一个元素-Town1。

因此,解决我的第一个问题和上面消息中的问题的最终类是:

namespace CpuRegistry.DataContexts
{
    public class CpuRegistryDb : IdentityDbContext<ApplicationUser>
    {
        public CpuRegistryDb()
            : base("DefaultConnection", throwIfV1Schema: false)
        {
        }

        public static CpuRegistryDb Create()
        {
            return new CpuRegistryDb();
        }

        public DbSet<Region> Regions { get; set; }
        public DbSet<District> Districts { get; set; }
        public DbSet<Town> Towns { get; set; }

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

            modelBuilder.Entity<Town>().HasMany<District>(t => t.Districts).WithOptional(d => d.Town);
            modelBuilder.Entity<District>().HasMany<Town>(d => d.Towns).WithOptional(t => t.District);            
        }
    }
}

namespace CpuRegistry.Models
{
    public enum TownType
    {
        Город, Посёлок, Село
    }

    public class Town
    {
        public int ID { get; set; }

        [Required]
        public string Name { get; set; }

        [Required]
        public int RegionID { get; set; }

        public int? DistrictID { get; set; }

        [Required]
        public TownType TownType { get; set; }

        public virtual ICollection<District> Districts { get; set; }
        public virtual Region Region { get; set; }
        public virtual District District { get; set; }

        public override string ToString()
        {
            return ID.ToString();
        }
    }

    public class District
    {
        public int ID { get; set; }

        [Required]
        public string Name { get; set; }

        [Required]
        public int RegionID { get; set; }

        public int? TownID { get; set; }

        public virtual ICollection<Town> Towns { get; set; }
        public virtual Region Region { get; set; }
        public virtual Town Town { get; set; }

        public override string ToString()
        {
            return ID.ToString();
        }
    }
}
namespace CpuRegistry.DataContexts
{
公共类CpuRegistryDb:IdentityDbContext
{
公共CpuRegistryDb()
:base(“DefaultConnection”,throwifvv1schema:false)
{
}
公共静态CpuRegistryDb Create()
{
返回新的CpuRegistryDb();
}
公共数据库集区域{get;set;}
公共数据库集区域{get;set;}
公共数据库集{get;set;}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
基于模型创建(modelBuilder);
modelBuilder.Entity()有许多(t=>t.Districts)。可选(d=>d.Town);
modelBuilder.Entity()有许多(d=>d.Towns)。带有可选(t=>t.District);
}
}
}
命名空间CpuRegistry.Models
{
公共枚举类型
{
Город, Посёлок, Село
}
公营城镇
{
公共int ID{get;set;}
[必需]
公共字符串名称{get;set;}
[必需]
public int RegionID{get;set;}
公共int?DistrictID{get;set;}
[必需]
公共TownType TownType{get;set;}
公共虚拟ICollection区域{get;set;}
公共虚拟区域{get;set;}
公共虚拟区区{get;set;}
公共重写字符串ToString()
{
返回ID.ToString();
}
}
公营学区
{
公共int ID{get;set;}
[必需]
公共字符串名称{get;set;}
[必需]
public int RegionID{get;set;}
公共int?TownID{get;set;}
公共虚拟ICollection{get;set;}
公共虚拟区域{get;set;}
公共虚拟城镇{get;set;}
公共重写字符串ToString()
{
返回ID.ToString();
}
}
}

谢谢@Hoborg的帮助。

public int?DistrictID
表示该城镇可以属于District(是District的一部分)<代码>公共虚拟ICollection Districts意味着该城镇可以有地区。在人类语言中:地区由城镇和地区划分。通常,该地区包括许多城镇。但有些大城镇不属于任何地区,而是按地区划分的@SergeyShambal在你解释之后,我更新了我的答案。这就是你需要的东西吗?如果是,那么你不认为这样的设计(一对多和反向多对一)看起来不太好吗?我尝试了你的解决方案,结果看起来像我需要的。非常感谢你。是的,我认为这样的设计不是一个好主意。但我上一条信息中的图表来自现实生活,我不知道如何用另一种方式来描述它。经过几天的开发,我遇到了一些问题。当我需要通过DropDownList设置Town-in-District模型时,该模型不会通过验证,因为DropDownList包含城镇的ID,但该模型等待完整类别的城镇。我将您的解决方案与我以前的变体相结合。我的下一个答案就是结果。
CreateTable(
                "dbo.AspNetUserRoles",
                c => new
                    {
                        UserId = c.String(nullable: false, maxLength: 128),
                        RoleId = c.String(nullable: false, maxLength: 128),
                    })
                .PrimaryKey(t => new { t.UserId, t.RoleId })
                .ForeignKey("dbo.AspNetRoles", t => t.RoleId, cascadeDelete: true)
                .ForeignKey("dbo.AspNetUsers", t => t.UserId, cascadeDelete: true)
                .Index(t => t.UserId)
                .Index(t => t.RoleId);
public class TestEfContext : ApplicationDbContext {
    public DbSet<Town> Towns { get; set; }
    public DbSet<District> Districts { get; set; }

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

        modelBuilder.Entity<Town>()
            .HasMany<District>(x => x.Districts)
            .WithOptional(x => x.Town);

        modelBuilder.Entity<District>()
            .HasMany<Town>(x => x.Towns)
            .WithOptional(x => x.District);
    }
}

public class Town {
    [Key]
    public int Id { get; set; }

    public District District { get; set; }

    public virtual ICollection<District> Districts { get; set; }

    public override string ToString() {
        return Id.ToString();
    }
}

public class District {
    [Key]
    public int Id { get; set; }

    public Town Town { get; set; }

    public virtual ICollection<Town> Towns { get; set; }

    public override string ToString() {
        return Id.ToString();
    }
}
using (var ctx = new TestEfContext()) {
            ctx.Towns.First().District = ctx.Districts.First();
        }
namespace CpuRegistry.DataContexts
{
    public class CpuRegistryDb : IdentityDbContext<ApplicationUser>
    {
        public CpuRegistryDb()
            : base("DefaultConnection", throwIfV1Schema: false)
        {
        }

        public static CpuRegistryDb Create()
        {
            return new CpuRegistryDb();
        }

        public DbSet<Region> Regions { get; set; }
        public DbSet<District> Districts { get; set; }
        public DbSet<Town> Towns { get; set; }

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

            modelBuilder.Entity<Town>().HasMany<District>(t => t.Districts).WithOptional(d => d.Town);
            modelBuilder.Entity<District>().HasMany<Town>(d => d.Towns).WithOptional(t => t.District);            
        }
    }
}

namespace CpuRegistry.Models
{
    public enum TownType
    {
        Город, Посёлок, Село
    }

    public class Town
    {
        public int ID { get; set; }

        [Required]
        public string Name { get; set; }

        [Required]
        public int RegionID { get; set; }

        public int? DistrictID { get; set; }

        [Required]
        public TownType TownType { get; set; }

        public virtual ICollection<District> Districts { get; set; }
        public virtual Region Region { get; set; }
        public virtual District District { get; set; }

        public override string ToString()
        {
            return ID.ToString();
        }
    }

    public class District
    {
        public int ID { get; set; }

        [Required]
        public string Name { get; set; }

        [Required]
        public int RegionID { get; set; }

        public int? TownID { get; set; }

        public virtual ICollection<Town> Towns { get; set; }
        public virtual Region Region { get; set; }
        public virtual Town Town { get; set; }

        public override string ToString()
        {
            return ID.ToString();
        }
    }
}