2016-01-13 16 views
16

In Entity Framework 7 quando sto cercando di applicare una migrazione ottengo l'erroreSpecificare ON DELETE NO ACTION in Entity Framework 7?

Introducendo vincolo FOREIGN KEY 'FK_ChangeOrder_User_CreatedByID' sul tavolo 'ChangeOrder' potrebbe causare cicli o più percorsi a cascata. Specificare ON DELETE NO ACTION o ON UPDATE NO ACTION o modificare altri vincoli FOREIGN KEY.
Impossibile creare il vincolo. Vedi errori precedenti.

conosco in versioni precedenti di Entity Framework si sarebbe occupato di questo con l'aggiunta

modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); 

alla DbContext ma in EF7 modelBuilder non sembra avere un .Conventions ad esso e Google è solo tornando anziani EF 4 anche se EF 6 risultati.

Come si specifica il vincolo ON DELETE NO ACTION in Entity Framework 7?

Modifica: La risposta fornita da Oleg lo farà apparentemente per Chiave esterna ma vorrei farlo globalmente poiché sarà molto più semplice utilizzare una riga di codice per dichiararla globalmente, quindi specificare il codice per ogni singola delle centinaia di relazioni che finirò per avere.

Edit 2: Codice di Oleg

public class ChangeOrder 
{ 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int ID { get; set; } 

    public Int16? ApprovedByID { get; set; } 
    public Byte ApprovalStatusID { get; set; } 
    public Int16 AssignedToID { get; set; } 
    public Int16 CreatedByID { get; set; } 
    public Byte CurrentStatusID { get; set; } 
    public DateTime? DateApproved { get; set; } 
    public DateTime? EndDate { get; set; } 
    public Byte ImpactID { get; set; } 
    public Byte PriorityID { get; set; } 
    public DateTime? StartDate { get; set; } 
    public Byte TypeID { get; set; } 

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

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

    [ForeignKey("ApprovedByID")] 
    public User ApprovedBy { get; set; } 

    [ForeignKey("ApprovalStatusID")] 
    public ChangeApprovalStatus ApprovalStatus { get; set; } 

    [ForeignKey("AssignedToID")] 
    public User AssignedTo { get; set; } 

    [ForeignKey("CreatedByID")] 
    public User CreatedBy { get; set; } 

    [ForeignKey("ImpactID")] 
    public ChangeImpact Impact { get; set; } 

    [ForeignKey("PriorityID")] 
    public ChangePriority Priority { get; set; } 

    [ForeignKey("TypeID")] 
    public ChangeType ChangeType { get; set; } 

    [ForeignKey("CurrentStatusID")] 
    public ChangeStatus CurrentStatus { get; set; } 
} 
public class JobSightDBContext : DbContext 
{ 
    protected override void OnModelCreating(ModelBuilder modelbuilder) 
    { 
     base.OnModelCreating(modelbuilder); 
    } 

    DbSet<ChangeApprovalStatus> ChangeApprovalStatus { get; set; } 
    DbSet<ChangeImpact> ChangeImapct { get; set; } 
    DbSet<ChangeOrder> ChangeOrders { get; set; } 
    DbSet<ChangePriority> ChangePriorities { get; set; } 
    DbSet<ChangeStatus> ChangeStatus { get; set; } 
    DbSet<ChangeType> ChangeTypes { get; set; } 
    DbSet<User> Users { get; set; } 
} 

risposta

25

Dopo scavare intorno su GitHut e lavorando con un ragazzo di brevetto molto da MS su GitHub la soluzione attuale è quella di aggiungere questo al DbContext

protected override void OnModelCreating(ModelBuilder modelbuilder) 
{ 
    foreach (var relationship in modelbuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys())) 
    { 
     relationship.DeleteBehavior = DeleteBehavior.Restrict; 
    } 

    base.OnModelCreating(modelbuilder); 
} 
+0

mi ha salvato la vita !!!!! Stavo ricevendo molti problemi di modellazione dell'FK. Grazie mille!!!!!!!!!!!!!! –

10

La costruzione

modelBuilder.Entity("myNamespace.Models.ChangeOrder", b => 
    { 
     b.HasOne("myNamespace.Models.User") 
      .WithMany() 
      .HasForeignKey("CreatedByID") 
      .OnDelete(DeleteBehavior.Cascade); 
    }); 

volontà significa creare FK_ChangeOrder_User_CreatedByID con REFERENCES [dbo].[User] ([CreatedByID]) ON DELETE CASCADE. Dovrebbe esistere in protected override void BuildModel(ModelBuilder modelBuilder) di YourContextModelSnapshot.cs creato durante la migrazione. Non sono sicuro di comprendere appieno la tua domanda, ma penso che dovresti aggiungere tale costrutto a XXXModelSnapshot.cs o rimuovere il costrutto non necessario, che esiste già qui.

AGGIORNATO: Vedo che avete il problema nel modello. Sono disponibili le seguenti proprietà nella

public Int16? ApprovedByID { get; set; } 
public Int16 AssignedToID { get; set; } 
public Int16 CreatedByID { get; set; } 

// navigation properties 

[ForeignKey("ApprovedByID")] 
public User ApprovedBy { get; set; } 

[ForeignKey("AssignedToID")] 
public User AssignedTo { get; set; } 

[ForeignKey("CreatedByID")] 
public User CreatedBy { get; set; } 

dalla migrazione di default cercare di impostare DeleteBehavior.Cascade su tutte le proprietà.

È possibile sovrascrivere il comportamento modificando OnModelCreating, che definisce sia DeleteBehavior.Restrict comportamento per tutti i tasti o per impostare su un unica chiave del comportamento DeleteBehavior.Cascade o DeleteBehavior.SetNull. Ad esempio, il codice utilizza DeleteBehavior.Cascade su CreatedByID (che crea ON DELETE CASCADE sulle chiavi esterne) e DeleteBehavior.Restrict su altre chiavi esterne (senza ON DELETE sulle chiavi esterne):

public class JobSightDBContext : DbContext 
{ 
    protected override void OnModelCreating(ModelBuilder modelbuilder) 
    { 
     base.OnModelCreating(modelbuilder); 

     modelbuilder.Entity(typeof (ChangeOrder)) 
      .HasOne(typeof (User), "ApprovedBy") 
      .WithMany() 
      .HasForeignKey("ApprovedByID") 
      .OnDelete(DeleteBehavior.Restrict); // no ON DELETE 
     modelbuilder.Entity(typeof (ChangeOrder)) 
      .HasOne(typeof (User), "AssignedTo") 
      .WithMany() 
      .HasForeignKey("AssignedToID") 
      .OnDelete(DeleteBehavior.Restrict); // no ON DELETE 
     modelbuilder.Entity(typeof (ChangeOrder)) 
      .HasOne(typeof (User), "CreatedBy") 
      .WithMany() 
      .HasForeignKey("CreatedByID") 
      .OnDelete(DeleteBehavior.Cascade); // set ON DELETE CASCADE 
    } 

    DbSet<ChangeApprovalStatus> ChangeApprovalStatus { get; set; } 
    DbSet<ChangeImpact> ChangeImapct { get; set; } 
    DbSet<ChangeOrder> ChangeOrders { get; set; } 
    DbSet<ChangePriority> ChangePriorities { get; set; } 
    DbSet<ChangeStatus> ChangeStatus { get; set; } 
    DbSet<ChangeType> ChangeTypes { get; set; } 
    DbSet<User> Users { get; set; } 
} 
+0

c'è un modo per fare questo a livello globale o devo farlo per ciascuna delle centinaia di rapporti che ho?Facendolo in questo modo creerò molto codice extra per me e preferirei evitare di farlo. – Matthew

+0

@MatthewVerstraete: È difficile rispondere avendo solo il messaggio di errore. Suppongo che tu abbia creato prima un insieme di classi che hanno molte notazioni di dati e poi creato 'XXXContext' derivato da' DbContext' che hanno molte proprietà come 'public DbSet Users {get; impostato; } ',' public DbSet ChangeOrders {get; impostato; } '. Suppongo che alcune definizioni in 'User',' ChangeOrder' saranno interpretate in modo errato da EF Migration, ma non posso indovinare cosa potrebbe essere esattamente. Uno per analizzare il modello completo per trovare la ragione. – Oleg

+0

Non sei sicuro di ciò che hai problemi di comprensione. Sto cercando la versione EF7 di 'modelBuilder.Conventions.Remove ();' ma ho aggiunto DBContext e un modello per te per guardare – Matthew