2013-02-11 5 views
7

Ich habe Probleme mit der umgekehrten Navigation auf einer meiner Entitäten.Eins-zu-Eins-Beziehung mit Entity Framework Fluent API

Ich habe die folgenden zwei Objekte:

public class Candidate 
{ 
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public long CandidateId { get; set; } 
    .... 

    // Reverse navigation 
    public virtual CandidateData Data { get; set; } 
    ... 

    // Foreign keys 
    .... 
} 

public class CandidateData 
{ 
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public long CandidateDataId { get; set; } 

    [Required] 
    public long CandidateId { get; set; } 

    // Foreign keys 
    [ForeignKey("CandidateId")] 
    public virtual Candidate Candidate { get; set; } 
} 

Nun mein Fremdschlüssel Navigation auf dem CandidateData Objekt funktioniert. Ich habe Probleme, die umgekehrte Navigation für das Kandidatenobjekt zu erhalten (wenn das überhaupt möglich ist).

Dies ist meine OnModelCreating Funktion:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); 

    modelBuilder.Entity<Candidate>() 
     .HasOptional(obj => obj.Data) 
     .WithOptionalPrincipal(); 

    base.OnModelCreating(modelBuilder); 
} 

Es liegt in der Nähe arbeiten, außer in der Datenbank habe ich zwei Spalten erhalten, die mit dem CandidateId verknüpfen. Ich bekomme die eine I vom POCO-Objekt die ich bekomme eine andere Spalte Candidate_CandidateId Ich nehme an, wurde vom ModelBuilder erstellt.

Ich bin im Moment leise verloren. Kann jemand bitte etwas Licht auf das werfen, was vor sich geht?

+0

Warum definieren Sie ein zusätzliches Feld wie [Erforderlich] public long CandidateId {get; einstellen; } Entfernen Sie es und Ihre Probleme werden –

+0

Ich denke, Ihre Beziehung sollte ModelBuilder.Entity sein () .HasOptional (obj => obj.Data) .WithRequired (e => e.Candidate); BTW: versuche nicht fließende API und Attribute zu mischen. – tschmit007

Antwort

13

Das One-to-One-Problem .... Das Problem ist EF und CODE Zuerst, wenn 1: 1, für die abhängigen einen Primärschlüssel, der sich auf den Prinzipal bezieht. Obwohl Sie eine DB anders und tatsächlich mit einer DB definieren können, können Sie sogar OPTIONAL FK auf der Primärseite haben. EF macht diese Einschränkung zuerst in Code. Fair enough denke ich ...

Vielleicht versuchen Sie Folgendes: IS haben ein paar Meinungen auf dem Weg gegeben, die Sie ignorieren können, wenn Sie nicht einverstanden sind :-)

using System.ComponentModel.DataAnnotations; 
using System.ComponentModel.DataAnnotations.Schema; 
using System.Data.Entity; 
namespace EF_DEMO 
{ 
class FK121 
{ 
    public static void ENTRYfk121(string[] args) 
    { 
     var ctx = new Context121(); 
     ctx.Database.Create(); 
     System.Console.ReadKey(); 
    } 
} 
public class Candidate 
{ 
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]// best in Fluent API, In my opinion.. 
    public long CandidateId { get; set; } 
// public long CandidateDataId { get; set; }// DONT TRY THIS... Although DB will support EF cant deal with 1:1 and both as FKs 
    public virtual CandidateData Data { get; set; } // Reverse navigation 

} 
public class CandidateData 
{ 
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] // best in Fluent API as it is EF/DB related 
    public long CandidateDataId { get; set; } // is also a Foreign with EF and 1:1 when this is dependent 
    // [Required] 
    // public long CandidateId { get; set; } // dont need this... PK is the FK to Principal in 1:1 
    public virtual Candidate Candidate { get; set; } // yes we need this 
} 
public class Context121 : DbContext 
{ 
    static Context121() 
    { 
     Database.SetInitializer(new DropCreateDatabaseIfModelChanges<Context121>()); 
    } 
    public Context121() 
     : base("Name=Demo") { } 
    public DbSet<Candidate> Candidates { get; set; } 
    public DbSet<CandidateData> CandidateDatas { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<Candidate>(); 

     modelBuilder.Entity<CandidateData>() 
        .HasRequired(q => q.Candidate) 
        .WithOptional(p=>p.Data) // this would be blank if reverse validation wasnt used, but here it is used 
        .Map(t => t.MapKey("CandidateId")); // Only use MAP when the Foreign Key Attributes NOT annotated as attributes 
    } 
} 

}

+0

Danke, das hat mehr oder weniger das Problem für mich gelöst. Obwohl ich immer noch gerne das CandidateId-Feld für mich zur Bearbeitung im laufenden Betrieb und ohne das Candidate-Objekt laden möchte. (Oder interpretiere ich das falsch?) Danke nochmal, William. – William

+0

Wenn Sie weiterhin den Fremdschlüssel möchten, können Sie CandidateId als Eigenschaft für CandidateData behalten und anstelle von .Map (t => t.MapKey ("CandidateId")) .HasForeignKey (t => t.CandidateId) Würde das nicht funktionieren? –

+0

@NathanaelSchulte Das geht leider nicht. Warum du das nicht kannst, habe ich keine Ahnung. Auf die .HasForeignKey() -Methode kann nur zugegriffen werden, wenn eine Viele verwendet wird. Das Problem mit dem Ansatz von phil soady besteht darin, dass der Fremdschlüssel, CandidateId, dann nicht als eine explizite Eigenschaft des Modells offengelegt werden muss, d. H. CandidateId kann nicht in der CandidateData-Klasse definiert werden. – Aernor

-2

Ich denke, dass der Fremdschlüssel wie folgt erstellt werden sollte: .Map (t => t.MapKey ("CandidateDataId")), weil dieser Fremdschlüssel in Kandidatentabelle platziert wird ...

Waht denkst du?