6

Sto sviluppando un'applicazione di plug-in con EF6, prima il codice.Entity Framework: condivisione di entità tra diversi DbContexts

Ho un contesto principale con un'entità chiamata User:

public class MainDataContext : DbContext 
{ 
    public MainDataContext(): base("MainDataContextCS") {} 
    public DbSet<User> Users { get; set; } 
} 

E poi un altro contesto per PluginX, su un altro progetto che fa riferimento alla base uno:

public class PluginDataContext : DbContext 
{ 
    public PluginDataContext() : base("MainDataContextCS") { 
    } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) { 
     modelBuilder.HasDefaultSchema("PluginX"); 
     base.OnModelCreating(modelBuilder); 
    } 

    public DbSet<Booking> Bookings { get; set; } 
} 

e questo crea ordinatamente, sullo stesso database (stessa stringa di connessione), la tabella PluginX.Bookings.

Il problema qui è che l'entità Booking contiene un riferimento a un'entità User:

public class Booking 
{ 
    public int Id { get; set;} 
    public virtual User CreationUser { get; set;} 
    public BookingStatus Status { get; set; } 
} 

E quando si esegue Add-Migration per il contesto plug-EF cercherà di creare un altro User entità chiamata PluginX.User.

Come può essere risolto? C'è un modo per condividere un'entità comune, in un altro DbContext?

+0

perché non ereditare PluginContext da MainContext. – hazimdikenli

risposta

5

Quando si lavora con più contesti si hanno due opzioni:

  1. trattare ogni contesto come se fossero applicazioni separate. Immagina che il tuo utente sia una risorsa esterna che ottieni da un servizio web. Non sarai in grado di aggiungere una chiave esterna a questo. Quello che dovresti fare in questo è aggiungere solo l'ID utente nelle tue tabelle e quando hai bisogno dei dettagli dell'utente chiama il servizio esterno per ottenerle o avere una copia locale dell'utilizzatore nel contesto di Bookings che aggiorneresti ogni tanto dal contesto Utenti.Questo approccio è utile quando si lavora con un sistema di grandi dimensioni e si desidera isolare le parti (leggi DDD e contesti limitati)
  2. Una parte dai 2 contesti, creare un terzo contesto con l'intero modello (utenti, prenotazioni, ecc.). Si utilizzerà il contesto completo per creare le migrazioni e mantenere la struttura del DB, ma nell'applicazione verranno utilizzati i contesti più piccoli. Questa è una soluzione molto semplice. È facile mantenere le migrazioni con un singolo contesto e consente comunque di isolare l'operazione DB in contesti più piccoli che non hanno accesso a entità non correlate.
1

Quando si aggiunge l'entità di prenotazione, non utilizzare il metodo DbSet.Add(). Utilizzare invece il metodo DbSet.Attach() e impostare la proprietà DbContext.Entry(Entity).State per la prenotazione su EntityState.Added e assicurarsi che l'DbContext.Entry(Entity).State per l'utente rimanga EntityState.Unchanged.

Così, per esempio, invece di fare questo:

pluginDataContext.dbBooking.Add(myNewBooking); 

fare questo:

pluginDataContext.dbBooking.Attach(myNewBooking); 
pluginDataContext.Entry(myNewBooking).State = EntityState.Added; 

Questo è perché il metodo Add() segna tutte le entità nel grafico oggetto come EntityState.Added che causerà inserti senza controllare se l'entità esiste già nel database. Il metodo Attach() fa semplicemente in modo che il contesto inizi a tracciare l'entità.

Questo è il motivo per cui non utilizzo quasi mai DbSet.Add().

2

Questa soluzione può essere d'aiuto: Entity Framework 6 Code First Migrations with Multiple Data Contexts. Tuttavia, in questo caso, entrambi i contesti sono nello stesso progetto. Non so se funziona con i contesti che sono in due progetti diversi (penso che dovrebbe essere se si utilizza la stessa classe per mappare l'utente). Come ha detto il blog, è necessario commentare il codice generato relativo alla tabella Users quando si esegue il comando Add-Migration per il contesto PluginX.

Problemi correlati