2016-03-03 11 views
12

Ich habe eine Datenbank-Setup mit 'Master/Slave-Replikation'. Ich habe einen Master und (mindestens) einen Slave, möglicherweise ℕ Slaves. Zur Vereinfachung von hier an werde ich über einen Master, einen Slave sprechen, weil die Bestimmung , die Slave zu verwenden, enthält einige Business-Logik nicht relevant für das eigentliche Problem zur Hand.Wie erreicht man Lese-Schreib-Trennung mit Entity Framework

Hier ist ein Schema der Einrichtung (mit n Slaves):

Overview

Bei der Anwendung (derzeit Dapper verwenden) Ich habe den folgenden, vereinfachte, Code:

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

Mein die Frage ist; Angenommen, ich möchte Entity Framework ("Code zuerst", falls relevant) anstelle von Dapper verwenden; Wie sollte ich am besten das gleiche Konzept erreichen? Einfügungen/Aktualisierungen/Löschungen werden für die Datenbank "Master" ausgeführt, und die Auswahl wird für einen Slave (oder einen der Slaves) ausgeführt. Unterstützt EF dieses Szenario überhaupt? Was müsste ich tun, damit dies funktioniert?


Zusatzinfo: Ich habe bereits nutzen ‚read-only‘ und ‚Nur Schreiben‘ Benutzer auf der SQL Server-Ebene als ‚letzte Verteidigungslinie‘ keine Fehler in der DAL zu verhindern. Was ich suche, ist eine Methode, meinen DAL einzuschränken, um SQL Server-Ausnahmen wegen "nicht erlaubter" Aktionen nicht abfangen zu müssen und erst einmal zum (inkorrekten) SQL-Server gehen zu müssen, bevor ich die gewünschte Aktion gefunden habe nicht erlaubt. I könnte den gleichen Ansatz wie ich jetzt verwenden; instanziieren/verwenden Sie den richtigen DbContext in der Methode selbst (listcustomers/updatecustomer im obigen Beispiel). Ich verstehe das. Aber das würde bedeuten, dass ich für jede "CRUD" -Aktion auf jeder "Entität" eine "Wrapper" -Funktion erstellen müsste, und das war einer der Gründe, warum ich überhaupt von Dapper zu EF wechselte. stellen Sie einfach ein DBSet zur Verfügung und lassen Sie EF die Changetracking-/SQL-Abfragen usw. machen und jetzt hoffentlich auch herausfinden, welche Verbindungszeichenfolge für jede Aktion verwendet werden soll.

+0

Der einfachste Weg, den ich schätze, ist, verschiedene Verbindungszeichenfolgen für jede Art von Situation zu geben. Also eine Lösung, die nicht auf der Ebene von Entity Framework, sondern auf der Ebene von SQL selbst ist. PS. Bitte benutzen Sie weiterhin dapper, godspeed – misha130

+1

@ misha130 Könnten Sie klären? Was würdest du als "Art der Situation" definieren? Und was würdest du als "auf dem Hebel von SQL selbst" definieren? – RobIII

+1

Sie müssen tatsächlich die Verbindungszeichenfolge zur Laufzeit ändern. Entity Framework bietet diese Möglichkeit. Diese Frage wird dir zeigen, wie! http://StackOverflow.com/Questions/22267949/entity-framework-change-connection-string-at-runtime – Gusdor

Antwort

1

Wie von anderen vorgeschlagen, erstellen Sie standardmäßig einen Lese-/Schreibkontext und erstellen dann einen schreibenden, der von diesem erbt. Stellen Sie außerdem sicher, dass Sie in einer partiellen Klasse einen Konstruktor implementieren, der auch eine andere Konfiguration akzeptiert.

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."); 
    } 
}