5

Es scheint mir, wie das ForeignKey Attribut ist für mich nicht funktioniert, aber ich denke, ich verwende es falsch;)Entity Framework-Code Erste Fremdschlüssel Ausgabe

Es ist einfacher, mit dem Code zu erklären:

public class BaseCard 
{ 
    public int Id {get ; set; } 
    public int BaseCardId { get; set; } 

    public List<Skill> Skills { get; set; } 
} 

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

    public int BaseCardId { get; set; } 
    [ForeignKey("BaseCardId")] 
    public BaseCard BaseCard { get; set; } 
} 

Wenn ich versuche, diese Objekte mit dem Samen Methode zu füllen, ich diesen Fehler:

INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.Skills_dbo.BaseCards_BaseCardId". The conflict occurred in database "Database", table "dbo.BaseCards", column 'Id'.

Es scheint mir, wie die ForeignKey in Skill Versuche an der Id Spalte von BaseCards anstelle der BaseCardId Spalte zu zeigen, und ich kann nicht herausfinden, warum ..

Wenn ich versuche, die „normale“ Id Eigenschaft BaseCard zu entfernen, und stellen Sie die BaseCardId als die PK (mit dem Attribute [Key]), erhalte ich folgende Fehlermeldung:

Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.

Wer weiß, wie ich diesen Code bekommen zu arbeiten, damit die Eigenschaft BaseCardId von der Skill Klasse zur BaseCardId Eigenschaft BaseCard zeigen wird, statt anscheinend die Id Eigentum?

Vielen Dank im Voraus!

+0

sehen, warum Sie Id und BaseCardId Felder in Ihrem BaseCard-Objekt haben? – Sefa

+0

@vgSefa Ich setze die BaseCardId auf eine bestimmte Nummer. Und die ID, dachte ich, wurde automatisch generiert. Aber es muss eine bestimmte Nummer sein. Ist es möglich, die ID auf eine bestimmte Nummer zu setzen? – Rob

+0

@vgSefa Ich habe versucht, die ID anstelle der BaseCardId auf die Nummern, die ich benötige, zu setzen, leider funktioniert das nicht. – Rob

Antwort

7

Es ist möglich, dass Sie die ID der BaseCard selbst festlegen, aber zuerst müssen Sie Fluent Api verwenden, um dies und die Eins-zu-viele-Beziehung anzugeben. Außerdem müssen Sie auf diese Weise keine Attribute in Ihren Modellklassen angeben. Ihre Modellklassen würde so aussehen:

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

    public virtual ICollection<Skill> Skills { get; set; } 
} 

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

    public int BaseCardId { get; set; } 
    public virtual BaseCard BaseCard { get; set; } 
} 

Wie Sie sehen können, habe ich die Navigationseigenschaften ändern virtual.If Sie Ihre Navigationseigenschaft als virtuelle EF definieren wird zur Laufzeit eine neue Klasse (dynamische Proxy) erstellen, die von Ihre BaseCard-Klasse und verwenden Sie sie stattdessen (das gleiche passiert mit Skill). Diese neue dynamisch erstellte Klasse enthält eine Logik zum Laden der Navigationseigenschaft, wenn sie zum ersten Mal aufgerufen wird. Diese Funktion wird als Lazy Loading bezeichnet. Sie ermöglicht Entity Framework, das Laden einer ganzen Baumstruktur abhängiger Objekte zu vermeiden, die nicht von der Datenbank benötigt werden. Sie können mehr Informationen über dieses Thema in diesen Pfosten finden: Why Navigation Properties are virtual by default in EF und Entity Framework 4.1 Virtual Properties.

Die andere Änderung, die ich in Ihrem Modell vorschlage, verwenden Sie ICollection <> geben Sie stattdessen List <> in der Eigenschaft Fähigkeiten. Wie Sie in dieser post sehen können, ist ein Interface in diesem Fall eine gute Übung. Sie können später die gewünschte Implementierung angeben (könnte eine Liste <> sein).

Nun zurück zu Ihrem Problem, in Ihrer Context-Klasse müssen Sie die OnModelCreating-Methode überschreiben, um die Beziehung und die Spalte no autogenerate für ID in der BaseCards-Tabelle anzugeben.

public class YourContext : DbContext 
{ 
    public DbSet<BaseCard> BaseCards { get; set; } 

    public DbSet<Skill> Skill { get; set; } 

    //... 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     // Configure the primary key for BaseCard 
     modelBuilder.Entity<BaseCard>().HasKey(t => t.Id); 
     //specify no autogenerate the Id Column 
     modelBuilder.Entity<BaseCard>().Property(b => b.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); 

     //one-to-many relationship 
     modelBuilder.Entity<Skill>().HasRequired(c => c.BaseCard) 
       .WithMany(s => s.Skills) 
       .HasForeignKey(c => c.BaseCardId); 
    } 
} 

Bei dieser Konfiguration müssen Sie immer die Id der BaseCard-Objekte mit einem anderen Wert einstellen.

Wenn Sie Daten Anmerkungen bevorzugen ist es möglich, das gleiche auf diese Weise angeben:

public class BaseCard 
{ 
    [Key, DatabaseGenerated(DatabaseGeneratedOption.None)] 
    public int Id { get; set; } 
    public virtual ICollection<Skill> Skills { get; set; } 
} 

public class Skill 
{ 
    [Key] 
    public int Id { get; set; } 

    public int BaseCardId { get; set; } 

    [ForeignKey("BaseCardId")] 
    public virtual BaseCard BaseCard { get; set; } 
} 

ist mein recomendation Fluent API verwenden, es ist flexibler und Sie müssen nicht Ihre Modellklassen berühren. Sie können einige nützliche cosiderations in diesem post

+0

Vielen Dank für die detaillierte Erklärung und geben mir mehr als 1 Option. Ich werde noch mehr recherchieren und sehen, welche ich verwenden werde. Danke noch einmal. – Rob

+0

octavioccl, Wenn ich die Fluent-API verwende, bekomme ich einen Fehler beim Aufruf der Update-Datenbank -verbose. Dies ruft die Seed-Methode von der Migration auf. Hier versuche ich, die Datenbank zu füllen, aber wenn ich eine BaseCard in den Kontext speichere, erhalte ich den folgenden Fehler: Kann keinen expliziten Wert für Identitätsspalte in Tabelle 'BaseCards' einfügen, wenn IDENTITY_INSERT auf OFF gesetzt ist. Liegt das daran, dass die OnModelCreating-Methode beim Migrieren zur DB nicht aufgerufen wird? Wie sonst schlagen Sie vor, dass ich die Datenbank füllen kann? – Rob

+0

Haben Sie die alte Datenbank gelöscht und eine neue erstellt ?. Ich denke, das liegt daran, dass Sie eine alte Datenbank mit der Spalte ID von BaseCards als Identität haben. – octavioccl