2011-11-21 3 views
14

Codice quadro entità In primo luogo è possibile generare il DB per i seguenti POCO.Codice struttura entità Primo: il vincolo FOREIGN KEY può causare cicli o più percorsi a cascata

public class Item { 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

public class ItemPair { 
    public int Id { get; set; } 

    public virtual Item FirstItem { get; set; } 
    public virtual Item SecondItem { get; set; } 
} 

vorrei stabilire la relazione con il Primo e il Secondo articolo tramite campi ID piuttosto che l'un'intera classe "Item". Quindi:

public class ItemPair { 
    public int Id { get; set; } 

    public virtual Item FirstItem { get; set; } 
    public int FirstItem_Id { get; set; } 

    public virtual Item SecondItem { get; set; } 
    public int SecondItem_Id { get; set; } 
} 

funziona anche. Modifica: questo in realtà non funzionava. Genera solo colonne aggiuntive FirstItem_Id1 e SecontItem_Id2.

Ma proprio la modifica delle proprietà di chiave esterna per FirstItemId, SecondItemId, (senza il trattino) in questo modo:

public class ItemPair { 
    public int Id { get; set; } 

    public virtual Item FirstItem { get; set; } 
    public int FirstItemId { get; set; } 

    public virtual Item SecondItem { get; set; } 
    public int SecondItemId { get; set; } 
} 

risultati nella seguente eccezione.

{"Introducing FOREIGN KEY constraint 'ItemPair_SecondItem' on table 'ItemPair' 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."} 

Perché? E cosa posso fare per evitare questa eccezione.

+0

Questa alternativa mi ha aiutato meglio http://stackoverflow.com/questions/19373310/introducing-foreign-key-constraint-may-cause-cycles-or-multiple-cascade-paths – Mzn

risposta

17

La mia aspettativa è che nel primo caso le proprietà Id non vengano utilizzate nel database poiché FK ed EF creeranno altre due colonne (è possibile convalidare forzando l'associazione della proprietà di navigazione con la proprietà FK utilizzando ForeignKeyAttribute). Nel secondo caso EF riconoscerà correttamente le proprietà ma utilizzerà anche la convenzione di eliminazione a cascata che causerà errori nel server SQL. Hai due proprietà dalla tabella che punta allo stesso genitore. In realtà nel database è possibile creare ItemPair dallo stesso Item (entrambi gli FK impostati con lo stesso Id). Se entrambe le relazioni hanno l'eliminazione a cascata abilitata, il risultato sarà in più percorsi a cascata => non consentiti nel server SQL.

La soluzione qui è mappatura fluente per definire manualmente come vengono mappate le relazioni. Here è l'esempio.

+0

Grazie mille per questo. Ho trascorso alcune ore cercando di capirlo. Non mi è venuto in mente di leggere le convenzioni di eliminazione a cascata. – Pauly

21

Ho deciso di rimuovere solo la convenzione di eliminazione a cascata.

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

     modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); 
     modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>(); 

    } 

Le ragioni sono:

  • preferisco segnare record eliminati o disattivati ​​a scopo di verifica.
  • Al massimo, elimino solo le tabelle di giunzione/mappatura.
  • Con un ORM È relativamente semplice eseguire il ciclo e cancellare i record figlio nel caso raro che sia necessario.

Grazie Ladislav Mrnka che mi sta indicando nella giusta direzione.

+0

Grazie a Dio, ho letto un'altra risposta a una domanda simile e ho pensato che avrei dovuto fare tutta la mia mappatura basata sugli attributi come fluente. IMHO, EF cerca di fare troppo per impostazione predefinita. – Josh

+0

Mi sono sentito allo stesso modo, quindi ho iniziato anche con la mappatura degli attributi. Tuttavia ora utilizzo i mapping Fluent API perché sembra darmi più controllo e mantenere il mio POCO libero da cruft.Prova a installare "Entity Framework Power Tools" e decodifica il database corrente. Penso che una volta che vedi i mapping che genera, non si sentirà così alieno. – Pauly

+0

Sembra fantastico! Ma sfortunatamente non ha funzionato nel mio caso. Quello che non capisco è come posso chiamare WillCascadeOnDelete (false) su ogni singola relazione, e rimuovere questa convenzione, e ancora nei miei script SQL (elenco dettagliato) posso vederlo creando il vincolo offensivo. Al di questo comando è "ON DELETE CASCADE", nonostante tutto il mio lavoro in mappature fluenti per eliminare questo comportamento. –