Как разрешить конкретную циклическую зависимость: DAL & Logging - PullRequest
2 голосов
/ 20 января 2009

Некоторые операции с данными «высокого риска» должны быть зарегистрированы. В этом случае операции «высокого риска» определяются как записи в нашу систему ERP. Случается, что мы регистрируем эти события в нашей базе данных SQL Server.

Псевдо-код:

Public Class MyCompany.DAL.ERP {
  Public void WriteToERP(string msg) {
    // ... do the write
    MyCompany.Logging.Write("Wrote msg: " + msg);
  }
}

Public Class MyCompany.Logging {
  Public void Write(string msg) {
    MyCompany.DAL.ExecuteSQL("Insert INTO EventLog VALUES " + msg);
  }
}

Какова наилучшая практика устранения этой жесткой связи?

Ответы [ 7 ]

3 голосов
/ 20 января 2009

Хм, ИМХО логирование - это проблема инфраструктуры. Вы можете использовать его в своем DAL, но ваш регистратор не должен использовать ваш DAL.

Если вы удалите зависимость вашего регистратора от вашего DAL, то вы сможете использовать свой регистратор и в других проектах.

1 голос
/ 20 января 2009

Вы можете создать собственный TraceListener (System.Diagnostics) для вставки в базу данных SQL Server вашей компании. Затем используйте Trace / TraceSource (System.Diagnostics) для входа в код вашего приложения. Затем вы можете использовать стандартную конфигурацию .NET, чтобы использовать свой собственный TraceListener во время разработки. Таким образом, если вам когда-либо понадобится изменить журнал событий, вам просто нужно изменить TraceListener. Кроме того, вы можете повторно использовать TraceListener в других приложениях.

Вы также можете использовать Блок приложения ведения журнала библиотеки предприятия и многие другие сторонние решения для ведения журнала.

0 голосов
/ 24 января 2009

Чтобы избежать циклической зависимости DAL -> Logger -> DAL, я бы предложил вам два уровня DAL: «простой DAL» и «протоколирование DAL».

«Простой DAL» - это просто DAL. «Ведение журнала DAL» основывается на «простом DAL»; он манипулирует БД с помощью простого DAL, а также записывает данные, снова используя простой DAL. Итак, у вас есть:

[логика приложения] --uses -> [протоколирование DAL] --uses -> [простой DAL] --uses -> DB

Если вы хотите делать с БД вещи, которые не нужно регистрировать (операции «низкого риска» ;-)), вы можете напрямую использовать «простой DAL» и обходить DAL при регистрации.

0 голосов
/ 20 января 2009

На самом деле, если под данными высокого риска вы подразумеваете критику / важно знать, как это должны быть данные, а также если вам нужно иметь журналы в базе данных (какие-то метаданные), то решение должно быть совершенно другим, как предлагали другие.

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

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

Невыполнение этого требования может иметь следующий побочный эффект:

  • Наличие только одной из данных или журнала, вставленных в базу данных.
  • Наличие только одной из данных или журнала, вставленных в базу данных перед другой, что означает, что система, основанная на том факте, что оба должны присутствовать в любой момент времени, может случайно выйти из строя в определенных обстоятельствах.
0 голосов
/ 20 января 2009

Похоже, что общим ответом среди ответов является предложение реализовать что-то вроде шаблона наблюдателя.

(Дайте мне знать, если есть лучшее резюме. Я обновлю соответственно.)

0 голосов
/ 20 января 2009

Ранее я развязывал эту ситуацию двумя способами: изменения статуса и запись событий.

Первый способ - создать интерфейс IHaveStatus, например:

/// <summary>
/// Interface for objects that have a status message 
/// that describes their current state.
/// </summary>
public interface IHaveStatus
{
    /// <summary>
    /// Occurs when the <seealso cref="Status"/> property has changed.
    /// </summary>
    event EventHandler<StatusChangedEventArgs> StatusChanged;
    /// <summary>
    /// The current status of the object.  When this changes, 
    /// <seealso cref="StatusChanged"/> fires.
    /// </summary>
    string Status { get; }
}

Когда ваш объект работает, вы устанавливаете свойство Status. Вы можете настроить свой установщик свойств для запуска события StatusChanged при его установке. Кто бы ни использовал ваши объекты, он может прослушивать событие, которое изменило ваш статус, и регистрировать все, что происходит.

Другая версия этого - добавить журнал событий к вашим объектам.

public event EventHandler<LogEventArgs> Log;

Принцип почти такой же, только ваши объекты будут менее болтливыми, чем журнал, управляемый Статусом (вы запускаете событие, только когда вы специально хотите что-то зарегистрировать).

Идея заключается в том, что вызывающие абоненты вне вашего DAL обязаны подключать эти события к надлежащему журналу (надеюсь, установленному с помощью DI). Ваш DAL не замечает, кто или что потребляет эти события, что хорошо разделяет эти проблемы.

0 голосов
/ 20 января 2009

Возможно, вы могли бы переместить компонент ведения журнала в отдельную сборку (я предполагаю, что это код C #), вызвать событие, на которое вызывающая сторона может зарегистрироваться до вызова Logging.Write (). После возврата Logging.Write () отмените регистрацию в событии. В обработчике событий вы можете выполнить ваш вызов MyCompany.DAL.ExecuteSQL («Вставить INTO EventLog VALUES» + msg).

...