xr2*_*0xr 5 sql-server entity-framework
我正在基于实体框架的应用程序中的共享数据库中隔离存储数据。我想使用 SQL Server 2016 行级安全性,但我更希望我的数据库连接都使用单个用户。因此,我想将 SQL Server CONTEXT_INFO设置为所有实体框架查询的商店编号。然后RLS 可以确定该行是否属于设置为CONTEXT_INFO 的商店编号。
我完成此操作的唯一想法是更新我的 DbContext 构造函数以创建连接本身并在将连接传递给基本构造函数之前执行 SET CONTEXT_INFO 语句。我想我可以在我的 DbContext 的部分类中添加一个构造函数重载来做到这一点,或者修改 t4 模板以这样生成原始构造函数。
EF 是否提供了更好的方法来做到这一点?我首先使用数据库。
IDbConnectionInterceptor每次打开连接时,它的实现者似乎都能够执行一些代码。这允许我执行一个存储过程来设置CONTEXT_INFOorSESSION_CONTEXT变量。我的拦截器看起来像这样:
public class MAContextInterceptor : IDbConnectionInterceptor
{
private static ITenantIDProvider _tenantIDProvider;
public MAContextInterceptor(ITenantIDProvider tenantIDProvider)
{
_tenantIDProvider = tenantIDProvider;
}
public void Opened(DbConnection connection, DbConnectionInterceptionContext interceptionContext)
{
// Set SESSION_CONTEXT to current tenant ID whenever EF opens a connection
try
{
Guid tenantID = _tenantIDProvider == null ? Guid.Empty : _tenantIDProvider.GetTenantID();
if (tenantID != Guid.Empty)
{
DbCommand cmd = connection.CreateCommand();
cmd.CommandText = "ma_setcontextinfo";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
DbParameter param = cmd.CreateParameter();
param.ParameterName = "@tenantID";
param.Value = tenantID;
cmd.Parameters.Add(param);
cmd.ExecuteNonQuery();
}
}
catch (System.NullReferenceException)
{
//log error
}
}
}
Run Code Online (Sandbox Code Playgroud)
由于这是在数据层类库中,我添加了一个ITenantIDProvider允许上面的层提供提供租户 ID 的实现。当应用程序启动时,这最终会在我的 Global.asax 中设置。它还调用System.Data.Entity.Infrastructure.Interception.DbInterception.Add(new MAContextInterceptor(tenantIDProvider));注册拦截器。
看起来它将适用于所有 DbContexts,我认为这是有问题的,但就我的目的而言,这是有效的。这个页面几乎说明了一切。在问这个问题之前,我不知道为什么它没有出现在我的任何搜索中!