[英]Entity Framework 6, Command Interception & Stored Procedures
我被要求在我的工作中為系統進行審計。 系統已經完成。 我認為EF 6的Command Intercept應該可以很好地達到我的目的。
但是,在某些情況下,我們想知道是誰發送了請假請求,並且我們希望能夠攔截此插入查詢。
using (DataContext context = new DataContext())
{
var result = context.CreateLeavePrerequest(
leaveRequest.LeaveType,
leaveRequest.StartDate,
leaveRequest.EndDate,
leaveRequest.NumberOfDays,
leaveRequest.EmployeeComment,
leaveRequest.HasSupportingDocumentation,
leaveRequest.ResourceTag,
leaveRequest.RemainingBalance,
leaveRequest.ApproverResourceTag,
leaveRequest.CapturerResourceTag,
leaveRequest.SupportingDocumentID,
ref id
);
那么存儲過程為:
CREATE PROCEDURE [dbo].[CreateLeavePrerequest]
(
@LeaveType VARCHAR(50) ,
@StartDate DATETIME ,
@EndDate DATETIME ,
@NumberOfDays DECIMAL(18, 5) ,
@EmployeeComment VARCHAR(512) ,
@SickNoteIndicator BIT ,
@ResourceTag INT,
@RemainingBalance DECIMAL,
@ApproverResourceTag INT,
@CapturerResourceTag INT,
@SupportingDocumentID INT,
@id INT = 0 OUT
)
AS
BEGIN
INSERT INTO [ESS PER LVE PreRequest]
( [Resource Tag] ,
[Leave Type] ,
[Start Date] ,
[End Date] ,
[No Of Days] ,
[Employee Comments] ,
[Sick Note Indicator],
[Status],
[Remaining Balance],
[Approver Resource Tag],
[Capturer Resource Tag],
[SupportingDocumentID]
)
SELECT @ResourceTag ,
@LeaveType ,
@StartDate ,
@EndDate ,
@NumberOfDays ,
@EmployeeComment ,
@SickNoteIndicator,
'Captured',
@RemainingBalance,
@ApproverResourceTag,
@CapturerResourceTag,
@SupportingDocumentID;
SELECT @id
END
更新:
CreateLeavePrerequest的實現如下:
public ISingleResult<CreateLeavePrerequestResult> CreateLeavePrerequest([global::System.Data.Linq.Mapping.ParameterAttribute(Name="LeaveType", DbType="VarChar(50)")] string leaveType, [global::System.Data.Linq.Mapping.ParameterAttribute(Name="StartDate", DbType="DateTime")] System.Nullable<System.DateTime> startDate, [global::System.Data.Linq.Mapping.ParameterAttribute(Name="EndDate", DbType="DateTime")] System.Nullable<System.DateTime> endDate, [global::System.Data.Linq.Mapping.ParameterAttribute(Name="NumberOfDays", DbType="Decimal(18,5)")] System.Nullable<decimal> numberOfDays, [global::System.Data.Linq.Mapping.ParameterAttribute(Name="EmployeeComment", DbType="VarChar(512)")] string employeeComment, [global::System.Data.Linq.Mapping.ParameterAttribute(Name="SickNoteIndicator", DbType="Bit")] System.Nullable<bool> sickNoteIndicator, [global::System.Data.Linq.Mapping.ParameterAttribute(Name="ResourceTag", DbType="Int")] System.Nullable<int> resourceTag, [global::System.Data.Linq.Mapping.ParameterAttribute(Name="RemainingBalance", DbType="Decimal(18,0)")] System.Nullable<decimal> remainingBalance, [global::System.Data.Linq.Mapping.ParameterAttribute(Name="ApproverResourceTag", DbType="Int")] System.Nullable<int> approverResourceTag, [global::System.Data.Linq.Mapping.ParameterAttribute(Name="CapturerResourceTag", DbType="Int")] System.Nullable<int> capturerResourceTag, [global::System.Data.Linq.Mapping.ParameterAttribute(Name="SupportingDocumentID", DbType="Int")] System.Nullable<int> supportingDocumentID, [global::System.Data.Linq.Mapping.ParameterAttribute(DbType="Int")] ref System.Nullable<int> id)
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), leaveType, startDate, endDate, numberOfDays, employeeComment, sickNoteIndicator, resourceTag, remainingBalance, approverResourceTag, capturerResourceTag, supportingDocumentID, id);
id = ((System.Nullable<int>)(result.GetParameterValue(11)));
return ((ISingleResult<CreateLeavePrerequestResult>)(result.ReturnValue));
}
更新2
在Global.asax中注冊DBCommandInterceptor:
protected void Application_Start()
{
DbInterception.Add(new Auditor());
}
DBCommandInterceptor的實現:
我迅速實現了這一點,以便可以看到是否可以攔截任何內容,因此它可以寫入“調試”窗口。 我已經能夠攔截一些Select
查詢,但這不是我們要審核的內容。
public class Auditor : IDbCommandInterceptor
{
public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
CreateAuditMessage(command, interceptionContext);
}
public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
CreateAuditMessage(command, interceptionContext);
}
public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
CreateAuditMessage(command, interceptionContext);
}
public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
CreateAuditMessage(command, interceptionContext);
}
public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
{
CreateAuditMessage(command, interceptionContext);
}
public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
{
CreateAuditMessage(command, interceptionContext);
}
public static void CreateAuditMessage<T>(DbCommand command, DbCommandInterceptionContext<T> interceptionContext)
{
string message;
var parameters = new StringBuilder();
foreach (DbParameter param in command.Parameters)
{
parameters.AppendLine(param.ParameterName + " " + param.DbType + " = " + param.Value);
}
if (interceptionContext.Exception == null)
{
message = (parameters.ToString() + " " + command.CommandText);
}
else
{
message = (parameters.ToString() + command.CommandText + " " + interceptionContext.Exception);
}
Debug.WriteLine(message);
}
}
最近,我讀了很多關於實體框架的文章,但是我不是很了解。 我已經實現了IDbCommandInterface並進行了注冊,等等。我能夠看到其他一些查詢被攔截,但是由於上述情況使得存儲過程被稱為“外部”,因此無法獲取參數。
這是一個簡單的例子。 並非系統中以類似方式調用的所有存儲過程都這么簡單。
改變上述情況以使我們可以應用攔截並進行審核的最佳方法是什么?
我更喜歡下面的方法從我的應用程序執行SQL存儲過程,因為我也使用這種方法從遠程服務器執行存儲過程。 您唯一需要注意的是將正確格式的參數傳遞給相應的Parameter類型。
using (SqlConnection con = new SqlConnection(dc.Con)) {
using (SqlCommand cmd = new SqlCommand("CreateLeavePrerequest", con)) {
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("@LeaveType", SqlDbType.VarChar).Value = leaveType;
cmd.Parameters.Add("@StartDate", SqlDbType.VarChar).Value = startDate;
cmd.Parameters.Add("@EndDate", SqlDbType.VarChar).Value = endDate;
cmd.Parameters.Add("@NumberOfDays", SqlDbType.VarChar).Value = numberOfDays;
cmd.Parameters.Add("@EmployeeComment", SqlDbType.VarChar).Value = employeeComment;
cmd.Parameters.Add("@SickNoteIndicator", SqlDbType.VarChar).Value = sickNoteIndicator;
cmd.Parameters.Add("@ResourceTag", SqlDbType.VarChar).Value = resourceTag;
cmd.Parameters.Add("@RemainingBalance", SqlDbType.VarChar).Value = remainingBalance;
cmd.Parameters.Add("@ApproverResourceTag", SqlDbType.VarChar).Value = approverResourceTag;
cmd.Parameters.Add("@CapturerResourceTag", SqlDbType.VarChar).Value = capturerResourceTag;
cmd.Parameters.Add("@SupportingDocumentID", SqlDbType.VarChar).Value = supportingDocumentID;
cmd.Parameters["@id"].Direction = ParameterDirection.Output;
con.Open();
cmd.ExecuteNonQuery();
}
}
對於任何NULL值,請檢查
DBNull.Value
讓我知道是否有幫助。 謝謝!
您始終可以使用Context Log屬性來使用DataContext
攔截任何數據庫查詢觸發
您可以在DataContext
類上定義一個構造函數,如下所示。
public class DataContext : DbContext, IDataContext
{
public DataContext(string nameOrConnectionString)
: base(nameOrConnectionString)
{
Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
//NOTE: Instead of Debug.WriteLine, you can stroe it in DB.
}
.....
.....
.....
}
上下文日志屬性記錄了什么?
適用於各種命令的SQL。 例如:
1-查詢,LINQ查詢,eSQL查詢和原始查詢。
2-在SaveChanges中生成的插入,更新和刪除
3-關系加載查詢,例如由延遲加載生成的查詢
了解更多信息。 記錄到不同的地方,結果記錄,格式化等,可以檢查記錄和攔截數據庫操作
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.