Col*_*lin 5 audit data-access-layer
我们最近将审核添加到了数据库中。一位同事使用触发器将其实现,并要求我在登录网站时调用存储过程。该存储过程将当前用户名和当前oracle会话ID插入表中,以便触发器可以将会话ID映射到用户名。问题是(或曾经)他假设用户的Internet会话已映射到数据库会话。事实并非如此,我们使用连接池,因此oracle会话ID可以映射到许多用户,而不必映射到在该会话上登录的用户。因此,我在数据访问层中创建了一个实用程序方法,该方法在每次插入,更新和删除时都调用他的过程(确保它在同一事务中):
/// <summary>
/// Performs an insert, update or delete against the database
/// </summary>
/// <param name="transaction"></param>
/// <param name="command">The command.</param>
/// <param name="transaction">A transaction, can be null.
/// No override provided without a transaction, to remind developer to always consider transaction for inserts, updates and deletes</param>
/// <returns>The number of rows affected by the operation</returns>
public static int InsertUpdateDelete(OracleCommand command, OracleTransaction transaction)
{
if (command == null)
throw new ArgumentNullException("command", "command is null.");
OracleConnection connection = null;
bool doCommit = false;
try
{
if (transaction == null)
{
//We always need a transaction for the audit insert
connection = GetOpenConnection();
transaction = connection.BeginTransaction();
doCommit = true;
}
command.Transaction = transaction;
command.Connection = transaction.Connection;
//TODO HttpContext requires that presentation layer is a website. So this call should NOT be in the data access layer.
string username = HttpContext.Current.User.Identity.Name;
if (!String.IsNullOrEmpty(username))
pInsertCurrentUserForAudit(username, command.Transaction);
int recordsAffected = command.ExecuteNonQuery();
if (doCommit)
transaction.Commit();
return recordsAffected;
}
finally
{
if (doCommit)
{
if (transaction != null)
transaction.Dispose();
if (connection != null)
connection.Dispose();
}
}
}
Run Code Online (Sandbox Code Playgroud)
这可以正常工作,并且审核现在可以按要求进行。但是,我不喜欢HttpContext的调用:
string username = HttpContext.Current.User.Identity.Name;
Run Code Online (Sandbox Code Playgroud)
这是执行任务的最快方法,但我不认为它应该在数据访问层中。如果在将来某个未知的时间我想使用表单应用程序访问数据库怎么办?访问HttpContext时会出现错误吗?有没有更好的方法来获取可以正确区分关注点的用户名?将用户名作为参数传递给每个插入,更新和删除是一个选项,但这将是一项艰巨的任务,我想知道是否有更优雅的方法。
你所做的绝对不是最好的方法,(正如你在上面的问题中概述的那样)这是被称为横切关注点的事情之一 - 其他事情是日志记录等)
使用的一种方法是传递实现所有此类横切关注点的功能的上下文对象,以便不必修改每一层中的每个方法来传递实现所需功能所需的数据。
否则,正如您所建议的,您将必须在每个需要它的方法中将用户名从堆栈的较高层传递到数据层。如果可能,一种替代方法是为所有此类方法(所有数据层方法)注入一个基类,并将该方法放入该基类中......