C# 如何在SQL Server中创建接受外部参数的触发器?

C# 如何在SQL Server中创建接受外部参数的触发器?,c#,sql,sql-server,C#,Sql,Sql Server,是否可以编写接受外部参数的触发器 主要原因是,我只能使用一个数据库用户连接到数据库。现在我正在开发一个数据库应用程序,并为每个单独的表创建了触发器来存储历史记录 在存储历史数据时,我想存储执行了插入、更新或删除操作的应用程序用户名。我本想使用User\u Name(),但后来知道,它只返回数据库用户,而不返回应用程序用户 因此,我正在寻找一些关于使用外部参数创建触发器的建议,以便将应用程序用户的id传递给该触发器。我想我已经清楚地解释了我的需求。提前谢谢 编辑 外部参数应该类似于存储过程参数,我

是否可以编写接受外部参数的触发器

主要原因是,我只能使用一个数据库用户连接到数据库。现在我正在开发一个数据库应用程序,并为每个单独的表创建了触发器来存储历史记录

在存储历史数据时,我想存储执行了
插入
更新
删除
操作的应用程序用户名。我本想使用
User\u Name()
,但后来知道,它只返回数据库用户,而不返回应用程序用户

因此,我正在寻找一些关于使用外部参数创建触发器的建议,以便将应用程序用户的id传递给该触发器。我想我已经清楚地解释了我的需求。提前谢谢

编辑
外部参数应该类似于存储过程参数,我们可以在其中传递值

Edit2
可能是我的描述不够清楚。所以我给你举个例子。
我正在开发的Web应用程序与帐户相关。因此,需要跟踪数据的更改。例如,会计人员可以更改员工的工资和佣金信息。如果输入/更新错误的信息,则总体财务结果将产生巨大的负面影响。现在在系统中,用户使用userid和password登录到系统,然后对员工信息进行一些更改。在这一阶段,我希望跟踪谁更改了员工信息、何时更改、更改前的值以及更改完成后的值。因此,将来如果出现任何问题,我可以通过证据找出犯错误的用户。

不一定要使用触发器完成,但也欢迎使用任何其他替代方法。

在每个表中存储用户名,并在数据更改期间将其作为参数传递。从那里,触发器可以将数据归档到另一个表中。

在您的位置,我将使用此示例,如果您的数据库中有人进行事件更新或选择,您将能够添加一些您想要的信息

示例表:

CREATE TABLE RAF1
(
strona NUMBER,
nazwa VARCHAR2(40)
);
示例触发器(如果您将nazw='same'write nazwa='roland'连接到此表,则此触发器将始终处于激活状态。您可以编辑此示例

create or replace TRIGGER sam 
BEFORE INSERT OR UPDATE OF nazwa
 ON RAF1 FOR EACH ROW WHEN (new.nazwa = 'same')
 BEGIN :new.nazwa := 'ronald'; END

您需要重新设计您的方法。数据库无法只了解您的应用程序用户信息。而且,不,您不能将参数传递给触发器。但您可以使用触发器引用自己的表,因此有一种方法


当您连接到数据库时,每个连接都会获得自己的进程id。您可以通过@spid获得该id

因此,当触发器触发时,您可以使用它来知道是哪个连接导致了更改

使用相同的数据库登录名可以有100个并发连接,每个连接都有自己的@spid值


但是,为了对您有用,您需要准备所有连接。每次建立连接时,您的应用程序都应该写入一个表,以记录应用程序使用该@@spid的内容

也许是像…这样简单的事情

CREATE TABLE
  map_spid_application_user (
    spid          BIGINT,
    application   VARCHAR(128),
    user          VARCHAR(128),
    PRIMARY KEY (spid)
  )
然后,在每个连接上运行类似这样的操作(可能通过存储过程)


然后,在触发器中,您可以引用/加入此表,以找出@spid引用的对象


您还可以变得更加智能,并使用类似的方法来永久记录用户连接的内容,如哪个spid。任何spid的当前用户将始终是具有最新连接日期时间的用户



那时你几乎可以做任何你喜欢的事情。因为你正在创建所有的信息,而不依赖数据库只知道@@spid以外的任何东西。

我已经完成了你所描述的。我不能说我对结果感到满意,因为当发生连接共享之类的奇怪事情时,解决方案可能相当脆弱嗯,这也只是感觉不对劲,但如果你愿意,试试看

  • 在应用程序端,将用户名填充到ConnectionString的AppName属性中
  • 在触发器中,引用App_Name()函数

  • 同样,这会满足您的要求,但我不建议这样做。最好只是将审核信息作为基本插入/更新内容的一部分从客户端或通过存储过程进行管理。

    因为触发器是按设计niladic模块,这意味着它们不支持参数。一种在外部级别a之间传递信息的技术niladic模块使用上下文信息或会话上下文

    Declare @mycontextinfo AS VARBINARY(128) = CAST('Application User Name' AS VARBINARY(128))
    SET CONTEXT_INFO @mycontextinfo;
    
    您可以从会话中的任何位置读取上下文信息,包括以下触发器:

    SELECT CAST(CONTEXT_INFO() AS VARCHAR(128)) AS mycontextinfo;
    
    另一个最复杂的方法是使用会话上下文

    EXEC sys.sp_set_Session_context @key = 'ApplicationUser', @value = 'XXX', @read_only = 1;
    
    然后,当需要从会话中的任何位置读取值时,请使用以下代码:

    SELECT SESSION_CONTEXT('ApplicationUser') AS [USER]
    

    请记住,这是在SQL Server 2016中添加的。

    什么是“应用程序用户ID”?它是SQL登录、Windows帐户还是其他?SYSTEM_USER是否返回您想要的?您从哪里获取应用程序用户?为什么不能在触发器中查找应用程序用户?可能重复使用
    上下文_INFO()
    ,请参阅使用此选项的答案链接。“应用程序用户ID”是用户登录系统时使用的登录id。该id存储在数据库表中。@V.P.Verma您仍然需要更精确,不清楚该登录名是SQL Server登录名、Windows帐户还是完全由您的应用程序管理的。如果是SQL或Windows,则system_用户将返回该id;如果是您的内部登录名你的申请,那么你需要遵循这里的其他建议之一(上面来自KM的关于usi的建议)
    SELECT SESSION_CONTEXT('ApplicationUser') AS [USER]