2013-04-02 13 views
12

Desidero inserire una stringa di connessione personalizzata nel mio contesto EF anziché utilizzare la stringa di connessione nel mio web.config. L'idea è di spostare tutta la logica relativa al database dal mio progetto MVC in un livello separato. Voglio anche che questo strato sia responsabile delle stringhe di connessione corrette invece delle mie applicazioni web.Inserire una stringa di connessione personalizzata in DbContext di Entity Framework

I servizi attualmente utilizzando il contesto stanno chiamando il costruttore di default:

using (var context = new MyDbContext()) { 
    //... 
} 

Il costruttore di default è chiamata internamente DbContext con il nome della stringa di connessione dal web.config:

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

    //... 
} 

Al fine per iniettare la mia stringa di connessione personalizzata mi servirebbe un costruttore sovraccarico che prende come argomento la stringa di connessione. Sfortunatamente non esiste un costruttore del genere.

E 'ovvio che l'aggiunta del sovraccarico costruttore manualmente proprio all'interno della classe MyDbContext sarebbe un pessima idea, dal momento che questa classe è generato automaticamente e sarà sovrascritto in qualunque momento presto. Non parliamo più di questo, è proibito. Periodo.

Poiché MyDbContext è una classe parziale, è possibile aggiungere il costruttore aggiuntivo in un file di classe separato partial class MyDbContext, ma anche questo sembra maleodorante. Non so perché, ma il mio cervello dice cattiva idea.

Dopo alcune indagini ho scoperto che si può dire a EF di includere questo costruttore aggiuntivo modificando il modello T4 Model.Context.tt che è un mix di C# e alcuni markup del modello. Ecco il costruttore originale:

public <#=Code.Escape(container)#>() 
    : base("name=<#=container.Name#>") 
{ 
<# 
    WriteLazyLoadingEnabled(container); 
#> 
} 

Ovviamente è facile aggiungere logica simile per generare un costruttore di overload contenente la stringa di connessione:

public <#=Code.Escape(container)#>(string nameOrConnectionString) 
    : base(nameOrConnectionString) 
{ 
<# 
    WriteLazyLoadingEnabled(container); 
#> 
} 

Ho provato questo e notato che sia ri-generare la le classi di modelli e l'aggiornamento del modello da DB saranno non influenzano il modello T4, quindi il costruttore aggiuntivo sarà sempre essere lì. Buona! A prima vista sembra una soluzione adatta, ma ...

E questa è la mia domanda: È davvero una buona soluzione?

Confrontiamo ancora una volta le tre opzioni:

  1. Modificare la classe auto-generata (ok, abbiamo deciso di dimenticare questo)
  2. Aggiungere il costruttore in un file di classe parziale
  3. Modificare il Modello T4 per dire a EF di generare il costruttore aggiuntivo

Da queste tre opzioni il terzo mi sembra la soluzione più comoda e pulita. Qual è la tua opinione? Qualcuno ha una buona ragione, perché questa sarebbe una cattiva idea? Ci sono più opzioni per iniettare stringhe di connessione, magari usando un custom connectionFactory? Se sì, come lo farei?

risposta

2

Dalle 3 opzioni forniti preferirei scegliere l'opzione 2. non ha la parola chiave parziale state introdotte per risolvere il problema con i file generati automaticamente? Usare i modelli T4 apporta ulteriore complessità a mio parere, lo sviluppatore di mantenimento deve comprendere una cosa in più (non tutti hanno familiarità con T4), ma estendere una classe parziale è lo sviluppo di C# più standard.

Tuttavia, non conosco la risposta a "c'è davvero una buona soluzione". L'introduzione di una fabbrica porta di nuovo un nuovo codice per mantenere, testare e capire, non sono sicuro che questa astrazione aiuti qui perché la fabbrica stessa bisogno di istanziare la DbContext con il costruttore appropriato (che è necessario fornire in ogni caso)

Edit:.

solo pensato su di esso una volta di più: la fabbrica potrebbe essere utile per risolvere la stringa di connessione da un altro percorso (si ha detto che non vuoi il connectiontring in web.config), ma che comunque non risolve il problema del costruttore

+1

In effetti utilizzo già una factory di stringhe di connessione, che ha rimosso con successo qualsiasi logica relativa all'accesso ai dati dai miei progetti di interfaccia utente e l'ho spostata dove appartiene, ovvero il progetto di accesso ai dati. Come hai detto, non ha risolto il problema del costruttore. – Jan

3

Come @shaftproposed, ho sostituito il mio approccio al modello T4 all'utilizzo di una classe parziale. Come si è scoperto, questo è davvero molto più semplice e intuitivo di qualsiasi altra soluzione che io conosca attualmente.

La classe auto-generata assomiglia:

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

    //... 
} 

Ho appena aggiunto un'altra classe parziale con lo stesso nome. Problema risolto.

public partial class MyDbContext 
{ 
    public MyDbContext(string nameOrConnectionString) 
      : base(nameOrConnectionString) 
    { 
    } 
} 
Problemi correlati