我使用'主/从复制'进行数据库设置。我有一个主人和(至少)一个奴隶,可能是ℕ奴隶。为简单起见,我将讨论一个主设备,一个从设备,因为确定使用哪个从设备包括一些与手头实际问题无关的业务逻辑。
这是设置的示意图(带有ℕ奴隶):
在应用程序中(当前使用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(“代码优先”,应该是相关的)而不是Dapper;我怎样才能最好地实现相同的概念;对“主”数据库执行插入/更新/删除,并对从属(或任何从属)执行选择。 EF是否支持这种情况?我需要做些什么来完成这项工作?
其他信息:我已经在SQL Server级别使用“只读”和“只写”用户作为“最后一道防线”,以防止DAL中出现任何错误。我正在寻找的是一种限制我的DAL的方法,以避免由于“不允许”操作而必须捕获SQL Server异常,并且在找到所需操作之前必须首先转到(不正确的)SQL服务器不允许。我可以使用与现在相同的方法;在方法本身中实例化/使用正确的DbContext(上例中的listcustomers / updatecustomer)。我明白了。但这意味着我必须为每个“实体”上的每个“CRUD”动作创建一个“包装”功能,这就是为什么我从一开始就从短小精悍到EF的原因;只需公开一个DBSet并让EF处理转换/ SQL查询等等,现在,希望还能找出每个动作使用哪个连接字符串。
答案 0 :(得分:4)
正如其他人所建议的那样,默认情况下创建一个读/写上下文,然后创建一个继承它的只读。 另外一定要在部分类中实现一个接受另一个配置的构造函数,如果你愿意的话。
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.");
}
}