我对创建可重用组件的最佳方法感到困惑,该组件依赖于某种持久化数据存储,例如数据库/实体框架。
例如说我想创建一个可重用的事件记录器,我只是通过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是实体。
答案 0 :(得分:2)
您应该使用自己的抽象将所有特定于持久性的代码提取到其类中。这样,您就可以拥有一个只包含记录器逻辑的记录器类,并且可以基于每个项目交换持久性实现。
但是,在您的示例中,SqlEventLogger
类仅包含与持久性相关的逻辑。如果这是实际情况,则无需提取该持久性逻辑,因为您最终会得到一个空记录器实现。因此,如果这是您的实际情况,IEventLogger
是唯一需要处理的抽象。您的可重用组件应该只包含IEventLogger
抽象,可能包含一个或多个默认实现。
这实际上是大多数日志记录框架的工作方式。在框架中使用默认SQL记录器时,使用普通SQL或存储过程可能更容易,并为程序包提供SQL脚本,以便用户可以创建所需的表和存储过程以使日志框架在一个问题中启动和运行分钟。
即使您使用实体框架,该EF模型也特定于您的实现,应该放在您的可重用库中。所以没有必要注入它。相反,用户应该为SQLEventLogger
提供连接字符串。但是,您仍然需要为用户提供SQL脚本。为了简化操作,您可以允许SqlEventLogger
为用户自动创建表(使用特定的配置开关时)。这也是SqlLoggingProvider的CuttingEdge.Logging所做的事情。