2015-07-09 11 views
6

Ich versuche, ein Entity-Framework-Code-erstes Modell aus einer vorhandenen Datenbank zu generieren (ohne das Datenbankschema zu ändern). Diese Datenbank wurde in der Vergangenheit verwendet, um edmx-Modelle zu generieren, und ich versuche, das entsprechende Modell mit Fluent Api oder Datenanmerkungen zu erreichen.EF-Code zuerst aus Datenbank 0..1 zu vielen Beziehung

Die Beziehung, die ich nicht reproduzieren konnte, ist 0..1 für viele, die eine Join-Tabelle verwenden (kein Nullable-Fremdschlüssel).

So wäre es etwa so aussehen:

TableA 
{ 
    ID (PrimaryKey) 
    TableB (0 or 1) 
} 

JoinTable 
{ 
    TableA_FK (PrimaryKey, ForeignKey), 
    TableB_FK (ForeignKey) 
} 

TableB 
{ 
    ID (PrimaryKey) 
    TableAs (Many) 
} 

Ist dies erreichbar im Code ersten Stil oder muß ich ein edmx Modell zu generieren, um diese Datenbank in EF zu verwenden, ohne das Schema zu ändern?

Vielen Dank, Phil

+0

Sie allllmost es mit [Entity Splitting] (https://msdn.microsoft.com/en-us/data/jj591617.aspx#2.7) tun könnte, aber ich denke, dass ein erfordert Zeile in der Join-Tabelle für jede Zeile in TabelleA – jjj

+0

Wie sieht das Datenbankmodell aus? Wenn 'JoinTable' ein PK/FK hat, das sich auf TabelleA bezieht, kann die Verknüpfung nur * (A) bis 0..1 (B) sein. –

+0

Habe ich es durcheinander gebracht? Grundsätzlich könnte A ein B haben (obwohl viele das nicht tun) B könnte viele As haben, obwohl die meisten keins haben. –

Antwort

0

Wenn ich es richtig verstanden habe, der folgende Code nur Daten Annotationen verwenden, sollten Sie Ihr Modell erstellen.

public class TableA 
{ 
    public int ID { get; set; } 

    public JoinTable JoinTable { get; set; } 
} 

public class TableB 
{ 
    public int ID { get; set; } 

    public List<JoinTable> JoinTables{ get; set; } 
} 

public class JoinTable 
{ 
    [Key, ForeignKey("TableA")] 
    public int TableA_FK { get; set; } 

    [ForeignKey("TableB")] 
    public int TableB_FK { get; set; } 

    public TableA TableA { get; set; } 

    public TableB TableB { get; set; } 
}  

Interessanterweise hat EF nicht eine Rundfahrt zurück zum Original durchführt, wenn Sie den Code ersten Modelle aus dem Datenbank-Modell generieren, die dieser Code erstellt dann EF das Modell vereinfacht und entfernt den Tisch sitzen und eine schafft NULL-fähiger Fremdschlüssel

Lassen Sie mich wissen, ob das funktioniert.

+0

Dies scheint nahe, was ich möchte. Es wäre eine vollständige Antwort, wenn TableA direkt auf seinen TableB verweisen könnte, ohne die Join-Tabelle zu durchlaufen. Dies geschieht in der Datenbank - zuerst EDMX-Modell Ansatz - die Join-Tabelle wird im Modell versteckt. –

+0

@PhilWithington Ja, ich weiß was du meinst.Ich bin mir nicht sicher, wie ich das erreichen soll. Sie könnten möglicherweise eine andere "NotMapped" -Eigenschaft haben, die die JoinTable-Eigenschaft dereferenziert. – user2697817

+0

Guter Vorschlag. Das Fehlen einer Hin- und Rückfahrt kann jedoch in der Zukunft problematisch sein. Danke für deine Gedanken. –

3

Hier ist ein Beispiel ohne Verwendung einer JoinTable-Klasse. Die Join-Tabelle wird über die flüssige API konfiguriert.

class DataContext : DbContext 
    { 
     public DataContext(string connectionString) 
      : base(connectionString) 
     { } 

     public DbSet<TableA> TableA { get; set; } 
     public DbSet<TableB> TableB { get; set; } 

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

      modelBuilder.Entity<TableA>().ToTable("TableA"); 
      modelBuilder.Entity<TableB>().ToTable("TableB"); 

      modelBuilder.Entity<TableB>() 
       .HasMany(x => x.TableAs) 
       .WithMany() 
       .Map(m => 
       { 
        m.ToTable("JoinTable"); 
        m.MapLeftKey("TableA_FK"); 
        m.MapRightKey("TableB_FK"); 
       }); 
     } 
    } 

    class TableA 
    { 
     public int ID { get; set; } 
     public TableB TableB { get; set; } 
    } 

    class TableB 
    { 
     public int ID { get; set; } 
     public ICollection<TableA> TableAs { get; set; } 
    } 

Dies generiert das folgende Migrationsskript, das wie das Schema aussieht, das Sie haben.

public override void Up() 
{ 
    CreateTable(
     "dbo.TableA", 
     c => new 
      { 
       ID = c.Int(nullable: false, identity: true), 
       TableB_ID = c.Int(), 
      }) 
     .PrimaryKey(t => t.ID) 
     .ForeignKey("dbo.TableB", t => t.TableB_ID) 
     .Index(t => t.TableB_ID); 

    CreateTable(
     "dbo.TableB", 
     c => new 
      { 
       ID = c.Int(nullable: false, identity: true), 
      }) 
     .PrimaryKey(t => t.ID); 

    CreateTable(
     "dbo.JoinTable", 
     c => new 
      { 
       TableA_FK = c.Int(nullable: false), 
       TableB_FK = c.Int(nullable: false), 
      }) 
     .PrimaryKey(t => new { t.TableA_FK, t.TableB_FK }) 
     .ForeignKey("dbo.TableB", t => t.TableA_FK, cascadeDelete: true) 
     .ForeignKey("dbo.TableA", t => t.TableB_FK, cascadeDelete: true) 
     .Index(t => t.TableA_FK) 
     .Index(t => t.TableB_FK); 

} 
+0

Sie haben zwei getrennte Beziehungen: ein 1: 1 zwischen TableA und TableB und viele: viele zwischen den gleichen Tabellen mit einer Join-Tabelle. – jjj

+0

Ja, aber kann das vermieden werden, wenn es mit dem Schema übereinstimmen muss? Nach meinem Verständnis entspricht dies dem in der Frage beschriebenen Schema. – Martin

+0

Dies ist die nächste Antwort, die ich zu dem, was ich erreichen möchte, gesehen habe. Ein Problem, das mir beim Betrachten des Codes auffällt, ist, dass der Primärschlüssel in der Join-Tabelle in der Migration nicht ganz richtig ist, aber dies ist möglicherweise kein Problem, da die Datenbank bereits existiert. –

0

Ich kann mich irren, aber ich glaube, dass Sie einige Konzepte sind hier fehlt ...

Warum haben Sie eine JoinTable wenn es hat keine Spalte neben der Fremdschlüssel? Es macht keinen Sinn ... IHMO ein Nullable Fremdschlüssel in TableA wäre der richtige Weg.

Wenn Sie mit Code-First arbeiten, bedeutet dies, dass alles in Ihrer Datenbank durch CODE repräsentiert wird. Es gibt keinen Grund, eine Tabelle in der Datenbank zu haben, aber nicht in Ihrem Code ...

EDMX behandelt, die eine Beziehung, weil es „Verbände“ verwendet https://msdn.microsoft.com/en-us/data/jj713299#Overview

... Sicherung auf die Code-first, können Sie repräsentieren Ihre Datenbank wie folgt aus:

public class JoinTable 
{ 
     [Key] 
     [DatabaseGenerated(DatabaseGeneratedOption.None)] 
     public int TableA_FK { get; set; } 

     public int TableB_FK { get; set; } 

     //a future property here 

     public virtual TableA TableA { get; set; } 

     public virtual TableB TableB { get; set; } 
} 

public partial class TableA 
{ 
     [Key] 
     [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
     public int TableAId { get; set; } 

     [Required] 
     [StringLength(50)] 
     public string Name { get; set; } 

     public virtual JoinTable JoinTable { get; set; } 
} 


public partial class TableB 
{ 
     public TableB() 
     { 
      JoinTable = new HashSet<JoinTable>(); 
     } 

     [Key] 
     [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
     public int TableBId { get; set; } 

     [Required] 
     [StringLength(50)] 
     public string Name { get; set; } 

     public virtual ICollection<JoinTable> JoinTable { get; set; } 
    } 
} 

public partial class Model1 : DbContext 
{ 
    public Model1() 
     : base("name=Model1") 
    { 
    } 

    public virtual DbSet<JoinTable> JoinTable { get; set; } 
    public virtual DbSet<TableA> TableA { get; set; } 
    public virtual DbSet<TableB> TableB { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 

     modelBuilder.Entity<TableA>() 
      .HasOptional(e => e.JoinTable) 
      .WithRequired(e => e.TableA); 

     modelBuilder.Entity<TableB>() 
      .HasMany(e => e.JoinTable) 
      .WithRequired(e => e.TableB) 
      .HasForeignKey(e => e.TableB_FK) 
      .WillCascadeOnDelete(false); 
    } 
} 
+0

Ich stimme zu, dass Nullable-Fremdschlüssel praktischer sind, besonders wenn man zuerst mit EF-Code arbeitet. Es kann jedoch in beiden Richtungen in Bezug auf die relationale Datenbank argumentiert werden, z.B. http://stackoverflow.com/questions/1723808/nullable-foreign-key-bad-practice. In meinem Fall muss ich jedoch Code aus einer bestehenden Datenbank zuerst zurückentwickeln. Ihre Lösung repräsentiert nicht das Modell, wie es edmx wäre. –

+0

Ich habe nie gesagt, dass meine Lösung das Modell darstellt, wie es edmx tut. Was ich gesagt habe, war, in meiner Meinung, der Edmx-Ansatz macht keinen Sinn, wenn Code-zuerst, weil es keinen Grund, eine Tabelle in Ihrer Datenbank, aber nicht in Ihrem Code –

+0

Eine viele zu viele Beziehung würde eine Tabelle in der erstellen Datenbank aber nicht im Modell würde es nicht? –

Verwandte Themen