2015-04-17 5 views
1

У меня есть две модели. Город:ASP.NET MVC каскад delete

using System; 
using System.Collections.Generic; 
using System.ComponentModel.DataAnnotations; 
using System.Data.Entity; 
using System.Linq; 
using System.Web; 

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 ICollection<Primary> Primaries { get; set; } 
    } 
} 

и Район:

using System; 
using System.Collections.Generic; 
using System.ComponentModel.DataAnnotations; 
using System.Linq; 
using System.Web; 

namespace CpuRegistry.Models 
{ 
    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 ICollection<Primary> Primaries { get; set; } 
    } 
} 

город может принадлежать округа. Disctrict может принадлежать городу. Также в округе может быть несколько городов, в городе может быть несколько районов. Как вы можете видеть, я обозначил DistrictID и TownID «?».

Когда я использую команду Add-Migration, Visual Studio создать миграционный файл, который содержит:

CreateTable(
       "dbo.TownDistricts", 
       c => new 
        { 
         Town_ID = c.Int(nullable: false), 
         District_ID = c.Int(nullable: false), 
        }) 
       .PrimaryKey(t => new { t.Town_ID, t.District_ID }) 
       .ForeignKey("dbo.Towns", t => t.Town_ID, cascadeDelete: true) 
       .ForeignKey("dbo.Districts", t => t.District_ID, cascadeDelete: true) 
       .Index(t => t.Town_ID) 
       .Index(t => t.District_ID); 

После выполнения команды Update-Database, у меня есть следующая ошибка:

Introducing FOREIGN KEY constraint 'FK_dbo.TownDistricts_dbo.Districts_District_ID' on table 'TownDistricts' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

Я видел это ссылка: Адрес Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths - why? из раствора:

You must either make the Stage optional in at least one of the entities (i.e. remove the [Required] attribute from the Stage properties)

B ut У меня нет атрибута [Обязательный]. Кроме того, я попытался это решение:

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); 
     } 

И есть ошибка:

CpuRegistry.DataContexts.IdentityUserRole: : EntityType 'IdentityUserRole' has no key defined. Define the key for this EntityType. CpuRegistry.DataContexts.IdentityUserLogin: : EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType. IdentityUserRoles: EntityType: EntitySet 'IdentityUserRoles' is based on type 'IdentityUserRole' that has no keys defined. IdentityUserLogins: EntityType: EntitySet 'IdentityUserLogins' is based on type 'IdentityUserLogin' that has no keys defined.

И когда я открываю миграции файл, который создает пользовательские таблицы, я увидел что-то похожее на мой код:

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); 

Но я не могу найти, как разработчики решили это в моделях или что-то еще.

Спасибо за помощь!

ответ

0

Таким образом, конечные классы, которые решают мой первый вопрос и проблемы из сообщений выше, являются:

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(); 
     } 
    } 
} 

Спасибо @Hoborg за помощью.

0

В соответствии с Configure Many-to-Many relationship using Code First Approach вам не требуется явно выраженное указание внешнего ключа public int? TownID { get; set; } в классе District и наоборот (в другом классе). Похоже, что Entity Framework может настроить все необходимые соединения (дополнительную таблицу в базе данных), используя только объявленные навигационные коллекции, например public virtual ICollection<Town> Towns { get; set; }.

Дополнение. Что вы имеете в виду, объявляя как одно свойство public int? DistrictID { get; set; }, так и коллекцию public virtual ICollection<District> Districts { get; set; }. Вы смешиваете концепции отношений «многие ко многим» в EF или вы имели в виду, что эти свойства обозначают что-то другое? Если они обозначают что-то другое, вы должны использовать Fluent API для их правильной настройки.

Обновление. После разъяснений 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(); 
    } 
} 

Таким образом

using (var ctx = new TestEfContext()) { 
      ctx.Towns.First().District = ctx.Districts.First(); 
     } 

предполагает, что Town1 будет иметь район = Distr1 и пустые Районы сбора в то время как Distr1 будет иметь Town = утратившим городов коллекцию с одним элементом - Town1.

+0

'public int? РайонID означает, что город может принадлежать к округу (быть частью района). 'public virtual ICollection Район означает, что город может иметь районы. В человеческом языке: регионы разделены городами и районами. Обычно в округе есть много городов. Но некоторые крупные города не принадлежат ни одному району и разделены по районам. –

+0

Я нарисовал [диаграмма] (https://drive.google.com/file/d/0B1bFjCWahknXSVhSRkczTWx2blE/view?usp=sharing). :) –

+0

@SergeyShambal Я обновил свой ответ после ваших объяснений. Это то, что вам нужно? Если да, то разве вы не думаете, что такой дизайн (один-ко-многим и обратный много-один) выглядит не очень хорошо? – Hoborg

Смежные вопросы