通过依赖项注入创建具有私有数据/EF存储的可重用组件



我为创建一个依赖于某种持久化数据存储(如数据库/实体框架)的可重用组件的最佳方法而烦恼。

例如,我想创建一个可重复使用的事件记录器,我只是通过nuget将其导入到我的项目中。我希望它将数据存储在主应用程序正在使用的同一数据库中,但我不想让记录器依赖于我的应用程序其他部分正在使用的数据上下文;这样做似乎会将组件与特定的应用程序联系起来。相反,我想知道它是否应该有自己的数据上下文,或者有另一个处理数据持久性的抽象。。。

我想我想问的问题是,当实体框架定义了我主要项目中的一堆具体内容时,我如何在使用实体框架时编程到通用接口。。。。?

public class SqlEventLogger : IEventLogger
{
    private DataContext _ctx;
    private Repository<ExceptionLog> repo;
    public SqlEventLogger(DataContext ctx)
    {
        _ctx = ctx;
        repo = new Repository<ExceptionLog>(ctx);
    }
    public void Log(string message, Severity severity, Exception exception = null, string requestType = null, string user = null, string location = null, string data = null)
    {
        repo.Add(new ExceptionLog
        {
            CreatedDate = DateTime.UtcNow,
            Message = String.Format("{0} || {1}", message, exception.Message),
            Source = exception.Source,
            StackTrace = exception.StackTrace,
            TargetSite = exception.TargetSite.ToString(),
            RequestForm = data,
            Url = location,
            RequestType = requestType,
            CurrentUser = user
        });
        _ctx.SaveChanges();
    }

本例中的DataContext是我的代码优先DbContext,ExceptionLog是实体。

您应该将所有特定于持久性的代码提取到具有自己抽象的类中。通过这种方式,您可以拥有一个只包含记录器逻辑的记录器类,并且可以在每个项目的基础上交换持久性实现。

然而,在您的示例中,SqlEventLogger类只包含与持久性相关的逻辑。如果这是实际情况,则不需要提取持久性逻辑,因为您最终会得到一个空的记录器实现。因此,如果这是您的实际情况,那么IEventLogger是唯一需要处理的抽象。您的可重用组件应该只包含IEventLogger抽象,也许还有一个或多个默认实现。

这实际上是大多数日志框架的工作方式。在框架中使用默认的SQL记录器时,使用纯SQL或存储过程并随包提供SQL脚本可能更容易,这样用户就可以创建所需的表和存储过程,以便在几分钟内启动并运行日志框架。

即使当您使用实体框架时,EF模型也是特定于您的实现的,应该放在您的可重用库中。因此不需要注入它。相反,用户应该为SQLEventLogger提供连接字符串。但是,您仍然需要为用户提供SQL脚本。为了让生活更轻松,您可以允许SqlEventLogger为用户自动创建表(当使用特定的配置开关时)。这也是CuttingEdge.Logging的SqlLoggingProvider所做的。

最新更新