如何使用Entity Framework实现读写分离

18

我使用了“主/从复制”设置的数据库。我有一个主数据库和(至少)一个从数据库,可能是ℕ个从数据库。为简单起见,下文中我将只讨论一个主数据库和一个从数据库,因为确定要使用哪个从数据库包含一些与实际问题无关的业务逻辑。

这是设置的示意图(带有ℕ个从数据库):

Overview

在应用程序中(当前使用Dapper),我有以下简化的代码:

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

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

我的问题是:假设我想使用Entity Framework(“Code First”,是否相关)而不是Dapper,我应该如何最好地实现相同的概念?在这种情况下,插入/更新/删除会针对“主”数据库执行,而选择操作将针对从服务器(或任何从服务器)执行。EF是否支持此方案?我需要做什么才能使其工作?


附加信息:我已经在SQL Server级别上使用“只读”和“只写”用户作为“最后一道防线”,以避免DAL中出现任何错误。我正在寻找一种限制我的DAL的方法,以避免因“不允许”的操作而捕获SQL Server异常,并首先访问(不正确的)SQL服务器,然后发现所需操作不被允许。我可以像现在一样使用相同的方法;在方法本身中实例化/使用正确的DbContext(例如上面的listcustomers/updatecustomer)。我明白了。但这意味着我必须为每个“CRUD”操作和每个“实体”创建一个“包装器”函数,这就是我一开始从dapper转向EF的原因;只需公开一个DBSet,并让EF处理changetracking / SQL查询等,现在,希望它也能确定每个操作要使用哪个连接字符串。


1
@misha130 你能澄清一下吗?你如何定义“情况类型”?你如何定义“在SQL本身的杠杆上”? - RobIII
1
你确实需要在运行时更改连接字符串。Entity Framework确实提供了这个功能。这个问题将向你展示如何做到!https://dev59.com/nmEh5IYBdhLWcg3wjUKJ - Gusdor
2
我不明白为什么这个问题因为“过于宽泛”而被暂停。 - RobIII
投票重新开放您的问题。 - Amit Verma
2
你可以通过重写 SaveChanges 来创建上下文,当某些条件为 false 时,它就不会调用 base.SaveChanges。但我不知道你能让它有多安全。也许可以基于数据库名称中的某些命名约定来实现? - Gert Arnold
显示剩余8条评论
1个回答

5

根据其他人的建议,创建一个默认的读写上下文,然后创建一个继承自它的只读上下文。 此外,如果您愿意,确保在部分类中实现接受另一个配置的构造函数。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接