C# 实体框架连接池:如何将用户ID注入SQL Server会话上下文?

C# 实体框架连接池:如何将用户ID注入SQL Server会话上下文?,c#,asp.net,sql-server,entity-framework,ado.net,C#,Asp.net,Sql Server,Entity Framework,Ado.net,我正在使用SQL Server开发一个多用户ASP.Net web应用程序(在开发者机器上运行v2016,在Azure上运行生产)。在我的应用程序中,我使用EF-6,只有一个技术用户连接到数据库。连接池处于活动状态 为了在这个应用程序中进行审计,我想将当前UserId添加到数据库每个表的一列中(我还想利用UserId做进一步的工作,但这不会给我的讨论增加任何价值) 由于我不想在我的应用程序的每个LINQ语句中传递UserId,因此我认为最好利用SQL Server会话上下文功能(如下所述),并通

我正在使用SQL Server开发一个多用户ASP.Net web应用程序(在开发者机器上运行v2016,在Azure上运行生产)。在我的应用程序中,我使用EF-6,只有一个技术用户连接到数据库。连接池处于活动状态

为了在这个应用程序中进行审计,我想将当前UserId添加到数据库每个表的一列中(我还想利用UserId做进一步的工作,但这不会给我的讨论增加任何价值)

由于我不想在我的应用程序的每个LINQ语句中传递UserId,因此我认为最好利用SQL Server会话上下文功能(如下所述),并通过在应用程序运行时将UserId设置为会话上下文变量来感知数据库状态

这样做之后,我就能够通过小型数据库函数GetUserId(从我的角度来看,这是一个非常健壮的解决方案)在表的user列的默认值内使用session_上下文变量。函数如下所示:

CREATE FUNCTION [dbo].[GetUserId] ()
RETURNS INT
AS
BEGIN
    -- -1 is means "unknown user" (e.g. for transactions executed via SQL Mgmt Studio)
    RETURN COALESCE(CAST(SESSION_CONTEXT(N'UserId') AS INT), -1)
END
现在我不确定的是:

在实体框架(或通常的ADO.Net)中插入my session_上下文变量的最佳点在哪里

目前,我覆盖了
DbContext
SaveChanges()
方法,并在调用基类
SaveChanges
之前执行一个存储过程:

    public override int SaveChanges()
    {
        SetUserIdContext();
        return base.SaveChanges();
    }

    private void SetUserId()
    {
        this.Database.OpenConnection();

        //Set the user context
        using (var cmd = this.Database.GetDbConnection().CreateCommand())
        {
            var parm = cmd.CreateParameter();
            parm.ParameterName = "@userId";
            parm.Value = this.UserId;

            cmd.CommandText = "SetUserId";
            cmd.CommandType = System.Data.CommandType.StoredProcedure;
            cmd.Parameters.Add(parm);

            cmd.ExecuteNonQuery();
        };
    }
目前,这种方法是可行的,但它肯定不是最好的方法。我想我可能会以某种方式覆盖构造函数,但我不知道如何正确地做到这一点。(另外,由于我不想停用连接池,覆盖connections open命令似乎也是错误的)

是否有人对如何或在何处注入存储过程调用有更好的想法,以便确保使用我的应用程序的用户的状态始终正确

注意:为了保证完整性,下面是我调用的用于设置用户ID的存储过程:

CREATE PROCEDURE [dbo].[SetUserId]
    @userId INT
AS
BEGIN
    SET NOCOUNT ON;

    EXEC sp_set_session_context 'UserId', @userId; 
END
非常感谢你在这方面的想法

干杯
Roland

在DbContext构造函数中打开连接,并在那里设置用户ID。除非长时间保持DbContext的活动状态(在ASP.NET应用程序中不应这样做),否则连接池不会受到显著影响

如何保证我在构造函数中打开的连接(并将用户ID传递给)与稍后在业务逻辑中的SaveChanges调用中使用的连接相同


如果连接在构造函数中显式打开(或打开并传递给构造函数),则DbContext不会关闭并重新打开它。

我理解并喜欢这种方法,但是,我已经了解到SaveChanges()方法实际上是隐式打开连接(或从连接池中获取连接)。如果这是正确的,那么我如何保证我在构造函数中打开的连接(并将用户ID传递给)仍然与稍后在我的业务逻辑中调用SaveChanges时使用的连接相同?@Roland see:太好了,谢谢!那这就是我要寻求的解决方案!