2016-03-03 10 views
12

Ho una configurazione del database che utilizza "replica master/slave". Ho un master e (almeno) uno slave, possibilmente ℕ slave. Per semplicità da qui in poi parlerò di un master, uno slave perché determinare che lo slave da utilizzare include alcune logiche di business non rilevanti per il problema attuale.Come ottenere separazione di lettura/scrittura con Entity Framework

Ecco uno schema del setup (con slave ℕ):

Overview

Nella domanda (attualmente in uso Dapper) Ho la seguente, semplificato, Codice:

abstract class BaseRepo 
{ 
    private readonly string _readconn; 
    private readonly string _writeconn; 

    public BaseRepo(string readConnection, string writeConnection) 
    { 
     _readconn = readConnection;  //Actually IEnumerable<string> for ℕ slaves 
     _writeconn = writeConnection; 
    } 

    private SqlConnection GetOpenConnection(string cnstring) 
    { 
     var c = new SqlConnection(cnstring); 
     c.Open(); 
     return c; 
    } 

    public SqlConnection GetOpenReadConnection() 
    { 
     return this.GetOpenConnection(_readconn); 
     // Actually we use some business-logic to determine *which* of the slaves to use 
    } 

    public SqlConnection GetOpenWriteConnection() 
    { 
     return this.GetOpenConnection(_writeconn); 
    } 
} 

class CustomerRepo : BaseRepo 
{ 
    // ...ctor left out for brevity... 

    // "Read" functions use the "read" connection 
    public IEnumerable<Customer> ListCustomers() 
    { 
     using (var c = this.GetOpenReadConnection()) 
     { 
      return c.Query<Customer>("select * from customers order by name") 
        .AsEnumerable(); 
     } 
    } 

    // "Write" functions use the "write" connection 
    public void UpdateCustomer(Customer cust) 
    { 
     using (var c = this.GetOpenWriteConnection()) 
     { 
      c.Execute("update customers set name = @name where id = @id", cust); 
     } 
    } 
} 

mio la domanda è; supponiamo di voler usare Entity Framework ("code first", dovrebbe essere rilevante) invece di Dapper; come farei meglio a raggiungere lo stesso concetto; inserimenti/aggiornamenti/eliminazioni vengono eseguiti rispetto al database "master" e le selezioni vengono eseguite su uno slave (o su uno qualsiasi degli slave). EF sostiene questo scenario? Cosa dovrei fare per farlo funzionare?


Ulteriori informazioni: Uso già 'sola lettura' e 'in sola scrittura degli utenti a livello di SQL Server come un 'ultima linea di difesa' per evitare che eventuali errori nel DAL. Quello che sto cercando è un metodo per limitare il mio DAL per evitare di dover intercettare le eccezioni di SQL Server a causa di azioni "non consentite" e dover andare al (SQL) server SQL (in primo luogo) prima di scoprire l'azione desiderata non autorizzato. I potrebbe utilizzare lo stesso approccio come faccio ora; istanziare/utilizzare il DbContext corretto nel metodo stesso (listcustomers/updatecustomer nell'esempio precedente). Ho capito. Ma ciò significherebbe che dovrei creare una funzione "wrapper" per ogni azione "CRUD" su ogni "entità" che era il motivo per cui stavo passando dapper a EF in primo luogo; esporre semplicemente un DBSet e fare in modo che EF si occupi delle query su changetracking/SQL ecc. e, si spera, anche di capire quale connectiontring usare per ogni azione.

+0

Il modo più semplice è quello di fornire stringhe di connessione diverse per ogni tipo di situazione. Quindi una soluzione che non è al livello di Entity Framework ma a livello di SQL stesso. PS. Per favore continua ad usare dapper, godspeed – misha130

+1

@ misha130 Potresti chiarire? Che cosa definiresti come "tipo di situazione"? E cosa definirebbe "sulla leva dello stesso SQL"? – RobIII

+1

In effetti è necessario modificare la stringa di connessione in fase di esecuzione. Entity Framework fornisce questa funzionalità. Questa domanda ti mostrerà come! http://stackoverflow.com/questions/22267949/entity-framework-change-connection-string-at-runtime – Gusdor

risposta

1

Come proposto da altri, creare un contesto di lettura/scrittura per impostazione predefinita e quindi creare un elemento di sola lettura che ne erediti. Assicurati anche di implementare in una classe parziale un costruttore che accetta un'altra configurazione, se lo desideri.

public partial class CustomerEntities : DbContext 
{ 
    protected CustomerEntities(string nameOrConnectionString):base(nameOrConnectionString) 
    {   
    } 
} 

public class ReadonlyCustomerEntities : CustomerEntities 
{ 
    public ReadonlyCustomerEntities() 
     : base("name=ReadonlyCustomerEntities") 
    {   
    } 

    public override int SaveChanges() 
    { 
     // Throw if they try to call this 
     throw new InvalidOperationException("This context is read-only."); 
    } 
} 
Problemi correlati