2015-07-09 17 views
6

Sto provando a generare un primo modello di codice del framework di entità da un database esistente (senza modificare lo schema del database). Questo database è stato utilizzato in passato per generare modelli edmx e sto cercando di ottenere il modello equivalente usando Fluent Api o annotazioni di dati.Codice EF dapprima dal database 0..1 a molte relazioni

La relazione non riesco a riprodurre è 0..1 per molti utilizzando una tabella di join (non una chiave straniera nullable).

Quindi sarebbe simile a questa:

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

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

TableB 
{ 
    ID (PrimaryKey) 
    TableAs (Many) 
} 

È questo realizzabile in primo stile codice o dovrò generare un modello di edmx al fine di utilizzare questo database in EF senza cambiare lo schema?

Molte grazie, Phil

+0

si potrebbe allllmost farlo con [Entità Splitting] (https://msdn.microsoft.com/en-us/data/jj591617.aspx#2.7), ma penso che richiede un riga nella tabella di join per ogni riga in TableA – jjj

+0

Che aspetto ha il modello di database? Se 'JoinTable' ha un PK/FK riferito alla tabellaA, l'associazione può essere solo * (A) a 0..1 (B). –

+0

Mi sono confuso? Fondamentalmente A potrebbe avere una B (anche se molti non lo fanno) B potrebbe avere molti come, anche se molti non ne hanno. –

risposta

0

Se ho capito bene, il seguente codice usando solo le annotazioni di dati dovrebbe creare il proprio modello.

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; } 
}  

È interessante notare che, EF non esegue un giro indietro a quello originale, se generate i modelli in codice prima dal modello di database che questo codice crea quindi EF semplifica il modello e rimuove la tabella unirsi e crea una chiave straniera nullable.

Fammi sapere se funziona.

+0

Questo sembra vicino a quello che vorrei. Sarebbe una risposta completa se TableA potesse riferirsi direttamente alla sua tabella B senza passare attraverso la tabella di join. Ciò accade nel primo approccio al modello edmx del database: la tabella dei join viene nascosta nel modello. –

+0

@PhilWithington Sì, so cosa intendi.Non sono sicuro di come farlo. Potresti avere un'altra proprietà 'NotMapped' che denota la proprietà' JoinTable'. – user2697817

+0

Buon suggerimento. Tuttavia, la mancanza di un viaggio di andata e ritorno potrebbe essere problematica in futuro. Grazie per i tuoi pensieri. –

3

Ecco un esempio senza utilizzare una classe JoinTable. La tabella di join è configurata tramite l'API fluente.

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; } 
    } 

Questo genererà il seguente script di migrazione, che assomiglia allo schema che si ha.

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

Si finisce con due relazioni separate: una 1: 1 tra TableA e TableB, e molte: molte tra le stesse tabelle utilizzando una tabella join – jjj

+0

Sì, ma può essere evitata se deve corrispondere allo schema? A mio avviso questo corrisponde allo schema descritto nella domanda. – Martin

+0

Questa è la risposta più vicina che ho visto su ciò che mi piacerebbe ottenere. Un problema che mi colpisce dall'osservare il codice è che la chiave primaria non è esattamente nella tabella di join nella migrazione ma potrebbe non essere un problema poiché il db esiste già. –

0

Posso sbagliarmi, ma credo che ti manca alcuni concetti qui ...

Perché avere un JoinTable se è non ha colonna oltre alle chiavi esterne? Non ha senso ... IHMO una chiave straniera nullable in TableA sarebbe il modo corretto.

Quando si lavora con Code-First vuol dire che tutto nel database sarà rappresentato dal CODICE. Non c'è alcun motivo per avere una tabella nel database, ma non nel codice ...

EDMX gestisce quel rapporto perché utilizza "Associazioni" https://msdn.microsoft.com/en-us/data/jj713299#Overview

... appoggiano al codice-prima, è possibile rappresentare il database in questo modo:

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

Concordo sul fatto che chiavi estranee nullable sono più pratiche, specialmente quando si lavora quando si utilizza prima il codice EF. Tuttavia può essere sostenuto in entrambi i modi in termini di database relazionale, ad esempio per es. http://stackoverflow.com/questions/1723808/nullable-foreign-key-bad-practice. Nel mio caso però ho bisogno di decodificare il codice prima da un db esistente. La tua soluzione non rappresenta il modello come avrebbe fatto l'approccio edmx. –

+0

Non ho mai detto che la mia soluzione rappresenti il ​​modello come fa edmx. Ciò che ho detto è, IN MIO PARERE, che l'approccio edmx non ha senso quando si utilizza il codice, perché non c'è motivo di avere una tabella nel database ma non nel proprio codice –

+0

Una relazione molti a molti creerebbe una tabella nel database ma non nel modello non sarebbe? –