C# 我可以在Entity Framework Core中的connect数据库上触发事件吗?
我有一个DbContext,所有的人都在访问我的Postgresql数据库,但当连接会话从数据库启动时,我需要运行一个小SQL命令。每次互动我都要这样做。更具体地说,它是一个用于设置用户名为logged的会话变量的函数 有可能在EF Core中做一些处理吗 --解决方案-- 我没有意识到我可以像bricelam说的那样在OnConfiguration中直接指定连接。我需要在每个连接中都这样做,因为它是会话的变量。它不是数据库的用户名,而是应用程序日志记录系统的用户名C# 我可以在Entity Framework Core中的connect数据库上触发事件吗?,c#,postgresql,entity-framework-core,C#,Postgresql,Entity Framework Core,我有一个DbContext,所有的人都在访问我的Postgresql数据库,但当连接会话从数据库启动时,我需要运行一个小SQL命令。每次互动我都要这样做。更具体地说,它是一个用于设置用户名为logged的会话变量的函数 有可能在EF Core中做一些处理吗 --解决方案-- 我没有意识到我可以像bricelam说的那样在OnConfiguration中直接指定连接。我需要在每个连接中都这样做,因为它是会话的变量。它不是数据库的用户名,而是应用程序日志记录系统的用户名 public Con
public ContratoInternetDbContext(DbContextOptions<ContratoInternetDbContext> options,
IOptions<AppSettings> configs)
: base(options)
{
_appSettings = configs.Value;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var conn = new NpgsqlConnection(_appSettings.ConnectionString);
conn.StateChange += (snd, e) =>
{
if ((e.CurrentState != e.OriginalState) && (e.CurrentState == ConnectionState.Open))
{
_cmmSetVarSession.ExecuteNonQuery();
}
};
optionsBuilder.UseNpgsql(conn);
_cmmSetVarSession = conn.CreateCommand();
_cmmSetVarSession.CommandText = "select sessao_set_var('usuario', 'CENTRAL_CLIENTE')";
}
public contractointernetdbcontext(DbContextOptions,
IOPS(配置)
:基本(选项)
{
_appSettings=configs.Value;
}
配置时受保护的覆盖无效(DBContextOptions Builder Options Builder)
{
var conn=新的NpgsqlConnection(_appSettings.ConnectionString);
连接状态更改+=(snd,e)=>
{
如果((e.CurrentState!=e.OriginalState)&&(e.CurrentState==ConnectionState.Open))
{
_cmmSetVarSession.ExecuteOnQuery();
}
};
选项生成器。使用NPGSQL(康涅狄格州);
_cmmSetVarSession=conn.CreateCommand();
_cmmSetVarSession.CommandText=“选择sessao_set_var('usuario','CENTRAL_CLIENTE')”;
}
您应该能够通过将连接传递到您的DbContext
并挂接StateChange
事件来实现这一点:(请原谅SQLite示例。我知道您说的是PostgreSQL。)
如果您使用的是EF Core 3.0或更高版本,您现在可以使用。执行所需操作的代码如下所示
public class DbUserIdProvider : DbConnectionInterceptor
{
// Called just after EF has called Open().
public override void ConnectionOpened(DbConnection connection, ConnectionEndEventData eventData)
{
base.ConnectionOpened(connection, eventData);
var cmd = connection.CreateCommand();
cmd.CommandText = "set session.client_user_id to 'myid'";
cmd.ExecuteNonQuery();
}
// Called just after EF has called OpenAsync().
public override Task ConnectionOpenedAsync(DbConnection connection, ConnectionEndEventData eventData, CancellationToken cancellationToken = default)
{
var cmd = connection.CreateCommand();
cmd.CommandText = "set session.client_user_id to 'myid'";
cmd.ExecuteNonQuery();
return base.ConnectionOpenedAsync(connection, eventData, cancellationToken);
}
}
services.AddDbContext<ApplicationDbContext>(options => options
.UseNpgsql(connection)
.AddInterceptors(new DbUserIdProvider()));
services.AddScoped<DbUserIdInterceptor>();
services.AddDbContext<ApplicationDbContext>((provider, options) =>
{
options.UseNpgsql(applicationSettings.ConnectionString());
// Resolve the DbUserIdInterceptor from the service provider
options.AddInterceptors(provider.GetRequiredService<DbUserIdInterceptor>());
});
public class DbUserIdInterceptor : DbConnectionInterceptor
{
UserInfoService userInfoService;
public DbUserIdInterceptor(UserInfoService uis)
{
userInfoService = uis;
}
// Called just after EF has called OpenAsync().
public override Task ConnectionOpenedAsync(DbConnection connection, ConnectionEndEventData eventData, CancellationToken cancellationToken = default)
{
var cmd = connection.CreateCommand();
cmd.CommandText = $"set session.client_user_id to '{userInfoService.uniqueName}'";
cmd.ExecuteNonQuery();
return base.ConnectionOpenedAsync(connection, eventData, cancellationToken);
}
}
当您使用异步方法访问数据库时,将调用ConnectionOpenedAsync()
要连接此拦截器以便上下文了解它,必须将其添加到Startup.cs中的AddDbContext调用中,如下所示
public class DbUserIdProvider : DbConnectionInterceptor
{
// Called just after EF has called Open().
public override void ConnectionOpened(DbConnection connection, ConnectionEndEventData eventData)
{
base.ConnectionOpened(connection, eventData);
var cmd = connection.CreateCommand();
cmd.CommandText = "set session.client_user_id to 'myid'";
cmd.ExecuteNonQuery();
}
// Called just after EF has called OpenAsync().
public override Task ConnectionOpenedAsync(DbConnection connection, ConnectionEndEventData eventData, CancellationToken cancellationToken = default)
{
var cmd = connection.CreateCommand();
cmd.CommandText = "set session.client_user_id to 'myid'";
cmd.ExecuteNonQuery();
return base.ConnectionOpenedAsync(connection, eventData, cancellationToken);
}
}
services.AddDbContext<ApplicationDbContext>(options => options
.UseNpgsql(connection)
.AddInterceptors(new DbUserIdProvider()));
services.AddScoped<DbUserIdInterceptor>();
services.AddDbContext<ApplicationDbContext>((provider, options) =>
{
options.UseNpgsql(applicationSettings.ConnectionString());
// Resolve the DbUserIdInterceptor from the service provider
options.AddInterceptors(provider.GetRequiredService<DbUserIdInterceptor>());
});
public class DbUserIdInterceptor : DbConnectionInterceptor
{
UserInfoService userInfoService;
public DbUserIdInterceptor(UserInfoService uis)
{
userInfoService = uis;
}
// Called just after EF has called OpenAsync().
public override Task ConnectionOpenedAsync(DbConnection connection, ConnectionEndEventData eventData, CancellationToken cancellationToken = default)
{
var cmd = connection.CreateCommand();
cmd.CommandText = $"set session.client_user_id to '{userInfoService.uniqueName}'";
cmd.ExecuteNonQuery();
return base.ConnectionOpenedAsync(connection, eventData, cancellationToken);
}
}
听起来像是XY问题:您正在询问如何执行Y,但问题出现在先前选择的路径X中。为什么必须设置此用户名、如何使用它以及为什么每次打开连接时都必须设置它?目前,此问题缺乏足够的上下文来回答。我认为您可以解决此问题,将事件处理程序添加到StateChange event的DbContext数据库属性中是否有方法将会话上下文设置为与连接打开“命令”相同的往返路径?Iúri dos Anjos,我认为在SQLServer的会话上下文中设置一个值只是一个DB函数调用。如果是这样的话,你应该可以用我在上面用不同的语句设置client\u user\u id的方法来完成。它将在每次打开数据库连接时执行。有关更多信息,请参阅本文