如何解决特定的循环依赖:DAL & 记录

发布于 2024-07-12 08:03:42 字数 456 浏览 8 评论 0原文

一些“高风险”的数据操作需要记录。 在这种情况下,“高风险”操作被定义为写入我们的 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);
  }
}

消除这种紧密耦合的最佳实践是什么?

Some "high risk" data operations need to be logged. In this case, the "high risk" operations are defined as writes to our ERP system. It happens that we are logging those events to our SQL Server database.

Pseudo-code:

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

What is the best practice to eliminate this tight coupling?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

天邊彩虹 2024-07-19 08:03:42

嗯,恕我直言,日志记录是一个基础设施问题。
您可以在 DAL 中使用它,但您的记录器不应使用您的 DAL。

如果您删除记录器对 DAL 的依赖关系,那么您也应该能够在其他项目中使用您的记录器。

Hmm, IMHO logging is an infrastructure concern.
You can use it in your DAL, but your logger should not use your DAL.

If you remove the dependency your logger has on your DAL, then you should be able to use your logger in other projects as well.

优雅的叶子 2024-07-19 08:03:42

您可以创建自定义 TraceListener (System.Diagnostics) 以插入公司的 SQL Server 数据库中。 然后使用 Trace / TraceSource (System.Diagnostics) 来记录应用程序的代码。 然后,您可以使用标准 .NET 配置在设计时使用自定义 TraceListener。 这样,如果您需要更改事件日志记录,则只需更改 TraceListener。 另外,您可以在其他应用程序中重用 TraceListener。

您还可以使用企业库的日志记录应用程序块和许多其他第 3 方日志记录解决方案。

You can create a custom TraceListener (System.Diagnostics) to insert into your company's SQL Server database. Then use Trace / TraceSource (System.Diagnostics) for your logging in your application's code. You can then use standard .NET configuration to use your custom TraceListener at design time. That way, if you ever need to change your event logging, you just have to change the TraceListener. Plus you could reuse the TraceListener in other applications.

You could also use the Logging Application Block of the Enterprise Library and many other 3rd party logging solutions.

墨落画卷 2024-07-19 08:03:42

我之前通过两种方式解耦了这种情况:状态更改和日志事件。

第一种方法是创建一个 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 不知道谁或什么正在消耗这些事件,这很好地区分了这些问题。

I've decoupled this situation before in two ways: Status changes and Log events.

First way is to create an IHaveStatus interface like such:

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

As your object does stuff, you set your Status property. You can configure your property setter to fire the StatusChanged event when you set it. Whoever uses your objects can listen to your status changed event and log everything that happens.

Another version of this is to add a Log events to your objects.

public event EventHandler<LogEventArgs> Log;

The principal is pretty much the same, only your objects would be less chatty than a Status-driven log (you only fire the event when you specifically want to log something).

The idea is that its the responsibility of callers outside of your DAL to hook these events up to the proper log (hopefully set by using DI). Your DAL is oblivious to who or what is consuming these events, which separates these concerns well.

冧九 2024-07-19 08:03:42

响应中的共同点似乎是建议实现观察者模式之类的东西。

(如果有更好的总结陈述,请告诉我。我会相应更新。)

The common thread among the responses seems to be the suggestion to implement something like the observer pattern.

(Let me know if there's a better summary statement. I'll update accordingly.)

夏有森光若流苏 2024-07-19 08:03:42

也许您可以将日志记录组件移至单独的程序集(我假设这是 C# 代码),引发一个事件,调用者可以在调用 Logging.Write() 之前注册该事件。 Logging.Write() 返回后,从事件中取消注册。 在事件处理程序中,您可以执行 MyCompany.DAL.ExecuteSQL("Insert INTO EventLog VALUES " + msg) 调用。

Maybe you could have your logging component, moved to a seperate assembly (I'm assuming this is C# code), raise an event, that the caller could register for before calling Logging.Write(). After Logging.Write() returns, unregister from the event. In the event handler you could execute your MyCompany.DAL.ExecuteSQL("Insert INTO EventLog VALUES " + msg) call.

鸩远一方 2024-07-19 08:03:42

实际上,如果您所说的高风险数据意味着关键/重要的是要知道它应该如何成为数据,并且如果您需要在数据库中保存日志(某种元数据),那么解决方案应该与其他人的建议完全不同。

我描述的情况意味着数据库事务的结果应该在任何给定时间都具有数据库中的日志数据和数据本身。 其中一项不应独立于另一项来完成。

因此,这种“日志记录”应作为单个数据库事务的一部分来完成,并且 DAL 应确保两个项目同时正确插入到同一事务中。

如果不这样做可能会产生以下副作用:

  • 仅将数据或日志之一插入数据库中。
  • 仅将其中一个数据或日志插入到数据库中,这意味着依赖于两者必须在任何给定时间都存在这一事实的系统可能会在特定情况下随机失败。

Actually, if by high-risk data you mean criticial/important to know it is how it is supposed to be data, and also if you need to have the logs in the database (some kind of meta-data), then the solution should be completely different as what others have suggested.

The situation I described would mean that the result of a database transaction should have both the logging data and the data itself in the database at any given time. One should not be done independently from the other.

As a result, this kind of "logging" should be done as part a single database transaction and the DAL should make sure that both items are inserted correctly at the same time in the same transaction.

Failure to do so could have the following side effect:

  • Having only one of the data or log inserted in the db.
  • Having only one of the data or log inserted in the db before the other, meaning that a system relying on the fact that both must be present at any given time might randomly fail in specific circumstances.
青瓷清茶倾城歌 2024-07-19 08:03:42

避免循环依赖 DAL -> 记录器-> DAL,我建议您有两层 DAL:“简单 DAL”和“记录 DAL”。

“简单DAL”只是一个DAL。 “logging DAL”建立在“simple DAL”之上; 它使用简单的 DAL 操作数据库,并且还使用简单的 DAL 记录内容。 所以你有:

[应用程序逻辑] --uses--> [记录 DAL] --使用 --> [简单DAL] --使用--> DB

如果您想对数据库执行不需要记录的操作(“低风险”操作;-)),您可以直接使用“简单 DAL”并绕过日志记录 DAL。

To avoid the circular dependency DAL -> Logger -> DAL, I'd propose you have two layers of DAL: "simple DAL", and "logging DAL".

The "simple DAL" ist just a DAL. The "logging DAL" builds on the "simple DAL"; it manipulates the DB using the simple DAL, and also logs stuff, again using the simple DAL. So you have:

[application logic] --uses--> [logging DAL] --uses--> [simple DAL] --uses--> DB

If you want to do stuff to the DB that does not need to be logged ("low risk" operations ;-)) you could use "simple DAL" directly and bypass the logging DAL.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文