2012-11-09 9 views
12

Sto utilizzando Entity Framework in codice prima di creare automaticamente il mio schema del database, e uno dei miei soggetti si presenta così:Perché il codice EF genera prima una colonna chiave esterna estranea?

public class AssessmentsCaseStudies { 
    #region Persisted fields 
    [Required] 
    [Key, Column(Order=0)] 
    [ForeignKey("Assessment")] 
    public int AssessmentId { get; set; } 

    [Required] 
    [Key, Column(Order=1)] 
    [ForeignKey("CaseStudy")] 
    public int CaseStudyId { get; set; } 

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

    [ForeignKey("Follows")] 
    public int? FollowsCaseStudyId { get; set; } 
    #endregion 

    #region Navigation properties 
    public virtual Assessment Assessment { get; set; } 
    public virtual CaseStudy CaseStudy { get; set; } 
    public virtual CaseStudy Follows { get; set; } 
    #endregion 
} 

Quando EF genera automaticamente il mio database, si genera una tabella con le seguenti colonne :

AssessmentId (PK, FK, int, not null) 
CaseStudyId (PK, FK, int, not null) 
Score (int, not null) 
FollowsCaseStudyId (FK, int, null) 
CaseStudy_CaseStudyId (FK, int, null) 

Questo va bene a parte la colonna CaseStudy_CaseStudyId. Perché è stato generato? Cosa serve? Come posso smettere di essere generato? Il mio sospetto è che EF non possa più abbinare automaticamente lo CaseStudy allo ICollection<AssessmentsCaseStudies> con la colonna CaseStudyId, quindi crea una propria colonna per collegare i due insieme per quella proprietà di navigazione.

+0

Non capisco davvero la risposta accettata a questa domanda. Ho esattamente due riferimenti 'CaseStudy' in 'AssessmentsCaseStudies', quindi non ho una vera relazione molti-a-molti e non vedo perché ho bisogno di una tabella di giunzione. Ho 'public virtual ICollection AssessmentsCaseStudies {get; impostato; } 'in' CaseStudy', però, quindi voglio un modo per dire che ICollection dovrebbe riguardare l'FK 'CaseStudyId', non l'FK 'FollowsCaseStudyId'. – Jez

+0

ok, ho pensato che potesse contenere informazioni utili. Puoi provare a creare un esempio ridotto, ad esempio con solo un'entità 'Assessment',' CaseStudy' e 'AssesmentCaseStudy', ognuno contenente solo un campo' ID' e 'AssesmentCaseStudy' contenenti un' AssesmentID' e un 'CaseStudyID 'campo? Il problema si verifica ancora? – CodeCaster

+1

Non penso che questa domanda avrebbe dovuto essere chiusa perché la risposta accettata alla domanda "dupe" non spiega bene le cose e mi piacerebbe una risposta migliore. Si prega di votare per riaprire. – Jez

risposta

7

Per qualche motivo, il suggerimento di attributo di Slauma InverseProperty non ha funzionato. Che cosa ha fatto il lavoro ero io che specifica la relazione tra i due CaseStudy proprietà di navigazione in AssessmentsCaseStudies, e l'entità CaseStudy, tramite l'API Fluente in OnModelCreating metodo di mio contesto di database:

modelBuilder.Entity<AssessmentsCaseStudies>() 
    .HasRequired(acs => acs.CaseStudy) 
    .WithMany(cs => cs.AssessmentsCaseStudies) 
    .HasForeignKey(acs => acs.CaseStudyId) 
    .WillCascadeOnDelete(false); 

modelBuilder.Entity<AssessmentsCaseStudies>() 
    .HasOptional(acs => acs.Follows) 
    .WithMany() // No reverse navigation property 
    .HasForeignKey(acs => acs.FollowsCaseStudy) 
    .WillCascadeOnDelete(false); 

Una volta che viene aggiunto, il codice di migrazione che viene generato quando I Add-Migration non tenta più di aggiungere la colonna CaseStudy_CaseStudyId e ho appena ottenuto la colonna FollowsCaseStudyId aggiunta, con la relazione di chiave esterna appropriata.

+0

Hai ricevuto un'eccezione con 'InverseProperty' attributo o hai ancora il terzo FK? Dovrebbe aver funzionato. Fa lo stesso del tuo mappaggio Fluent - con un'eccezione: l'attributo non disabilita l'eliminazione a catena per la prima relazione (perché la seconda eliminazione a catena è disattivata di default in ogni caso perché è una relazione opzionale). – Slauma

+0

Ha ancora creato il terzo FK. – Jez

16

Perché hai due proprietà di navigazione di tipo CaseStudy nel AssessmentsCaseStudies entità e una collezione AssessmentsCaseStudies nel CaseStudy entità EF non può decidere quale dei due CaseStudy proprietà di navigazione di questa collezione si riferisce. Entrambi potrebbero essere possibili e entrambe le opzioni comporterebbero un modello di entità valido ma diverso e uno schema di database.

In una situazione così ambigua la convenzione EF è quello di creare realtà tre relazioni, vale a dire la vostra collezione in CaseStudy non riferirsi a qualsiasi delle due CaseStudy proprietà di navigazione, ma ha un terzo (ma non esposta e "invisibile") endpoint in AssessmentsCaseStudies. Questa terza relazione è la ragione per la terza chiave esterna che stai vedendo nel database - quella con il carattere di sottolineatura. (La sottolineatura è sempre una forte indicazione che qualcosa happend per convenzione la mappatura e non dalla configurazione di dati o annotazioni esplicite.)

per risolvere il problema e per ignorare la convenzione è possibile applicare l'attributo [InverseProperty], specificando in tal modo la CaseStudy navigazione di proprietà della collezione AssessmentsCaseStudies appartiene:

[InverseProperty("AssessmentsCaseStudies")] // the collection in CaseStudy entity 
public virtual CaseStudy CaseStudy { get; set; } 

È anche possibile (in alternativa, non hai bisogno di entrambi) mettere l'attributo sul lato collezione:

[InverseProperty("CaseStudy")] // the CaseStudy property in AssessmentsCaseStudies entity 
public virtual ICollection<AssessmentsCaseStudies> AssessmentsCaseStudies { get; set; } 
+0

Ho a che fare con qualcosa di simile - Ho provato il tuo suggerimento ma ho ottenuto un'eccezione. Se hai un minuto: http://stackoverflow.com/questions/19802324/why-is-this-column-getting-generated-in-ef-code-first-migrations – RobVious

0

Per chiunque altro stia cercando una soluzione, se hai già provato le risposte precedenti e ottieni ancora una colonna chiave esterna aggiuntiva, cerca le proprietà che potresti aver definito più in basso nella tua classe POCO che non avevi intenzione di per mappare ai campi DB. Anche se contengono blocchi di codice, come con accessori get complessi, Entity Framework proverà a mapparli in qualche modo nel database. Ciò può causare colonne chiave esterne aggiuntive se le proprietà restituiscono entità. Per sicurezza, puoi decorare tali proprietà con l'attributo [NotMapped] o convertirle in metodi.

Problemi correlati