Entity Framework 6, Перехват команд и хранимые процедуры - PullRequest
0 голосов
/ 13 февраля 2019

Меня попросили разработать аудит системы для моей работы.Система уже была завершена.Я думаю, что командный перехват EF 6 должен хорошо работать для моих целей.

Однако существуют ситуации, подобные этой, когда мы хотели бы знать, кто отправил запрос на отпуск, и мы хотели бы иметь возможность перехватить эту Вставкузапрос.

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

Регистрация DBCommandInterceptor в Global.asax:

 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);
    }
}

В последнее время я много читал о Entity Framework, но я не очень хорошо осведомлен.Я реализовал IDbCommandInterface и зарегистрировал его и т. Д. Я могу видеть, что некоторые другие запросы перехватываются, но, поскольку описанная выше ситуация такова, что хранимая процедура вызывается «извне», я не могу получить параметры.

Это простой пример.Не все хранимые процедуры, которые вызываются аналогичным образом в системе, настолько просты.

Как лучше всего изменить вышеуказанную ситуацию, чтобы мы могли применить перехват и, следовательно, аудит?

Ответы [ 2 ]

0 голосов
/ 19 февраля 2019

Вы всегда можете использовать Свойство журнала контекста для перехвата любого из запросов к БД, используя 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.

    }
.....
.....
.....
}

Что регистрируется свойством Context Log?

  • SQL для команд всех типов.Например:

    1- Запросы, LINQ-запросы, eSQL-запросы и необработанные запросы.

    2- Вставляет, обновляет и удаляет сгенерированные как часть SaveChanges

    3-Запросы загрузки отношений, например, сгенерированные отложенной загрузкой

  • Параметры
  • Независимо от того, выполняется ли команда асинхронно
  • Отметка времени, указывающая, когда команда начала выполняться
  • Независимо от того, была ли команда выполнена успешно, не выполнена ли из-за исключения или для асинхронной работы была отменена
  • Некоторое указание значения результата
  • Примерное времяпотребовалось выполнить команду.Обратите внимание, что это время от отправки команды до возврата объекта результата.Это не включает время, чтобы прочитать результаты.

Чтобы узнать больше о.Ведение журнала в разных местах, ведение журнала результатов, форматирование и т. Д., Вы можете проверить Ведение журнала и перехват операций с базой данных

0 голосов
/ 19 февраля 2019

Я бы предпочел следующий подход для выполнения хранимых процедур SQL из моего приложения, так как я использовал это также для выполнения хранимых процедур с удаленных серверов.Единственное, что вам нужно позаботиться - это передать правильно отформатированные параметры в соответствующий тип параметра.

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

Дайте мне знать, если это поможет.Спасибо!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...