C# 我可以在Entity Framework Core中的connect数据库上触发事件吗?

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

我有一个DbContext,所有的人都在访问我的Postgresql数据库,但当连接会话从数据库启动时,我需要运行一个小SQL命令。每次互动我都要这样做。更具体地说,它是一个用于设置用户名为logged的会话变量的函数

有可能在EF Core中做一些处理吗

--解决方案--

我没有意识到我可以像bricelam说的那样在OnConfiguration中直接指定连接。我需要在每个连接中都这样做,因为它是会话的变量。它不是数据库的用户名,而是应用程序日志记录系统的用户名

    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的方法来完成。它将在每次打开数据库连接时执行。有关更多信息,请参阅本文