在c#console application

时间:2016-04-06 01:17:17

标签: c# entity-framework ado.net entity-framework-5 dbcontext

我正在开发一个c#控制台应用程序,我使用实体框架5.0作为sql server的数据访问层。现在我想跟踪更改并将它们保存在日志表中。所以这样做我发起了2个DbContext对象,一个用于业务数据,另一个用于日志数据,如下所示:

class Sync
    {
        static void Main(string[] args)
        {
            string syncResult = "Sync started";
            Entities entities = new Entities();//for business data
            Entities entities2 = new Entities();//for logs
            try
            {
              //code goes here
              entities.SaveChanges();
            }
            catch (Exception e)
            {
                syncResult = string.IsNullOrEmpty(e.Message) ? "Error" : e.Message;

            }
            entities.Dispose();
            entities2.LogHistories.Add(new LogHistory() { Description = syncResult });
            entities2.SaveChanges();
            entities2.Dispose(); 

现在我为我的日志提供了单独的DbContext对象,原因如下: -

  1. 如果我的第一个实体对象由于任何原因(例如未处理的验证错误或尝试破解系统等)而无法保存更改,则第二个实体2仍将能够保存日志条目。让我们举个例子。假设我正在使用第三方API进行集成,我期望它们以特定格式返回JSON。现在让我们假设返回json对象缺少数据,在这种情况下,当我尝试添加它将引发的对象时...现在因为我有日志的单独实体对象,所以日志条目将被保存(不会受到任何业务数据异常的影响)。但如果我有一个DBContext对象,那么日志条目将无法保存,因为我无法保存业务数据..所以我的问题是,如果启动2个DBContext对象一个用于日志而另一个用于业务数据是一个有效的方法跟随,或者是一个不好的决定?

4 个答案:

答案 0 :(得分:6)

不要使用2个上下文,您应该使用记录器(例如log4net with AdoNetAppender)。正如Evk在下面的评论中指出的那样,当您调用SaveChanges()时,EF会自动将所有内容包装到事务中,因此一旦发生错误,就不会将任何内容提交到数据库,您可以记录错误。例如:

static void Main(string[] args)
{
    ILog log = LogManager.GetLogger("Entities");

    using(var ctx = new Entities())
    {
        try
        {
            ...
            ctx.SaveChanges();
        }
        catch(Exception ex)
        {
           log.Error(ex.Message);
        }
    }
}

通过这种方式,您的应用程序保持干净,只有在SaveChanges()块结束时调用using并且仅在发生异常时才记录,所有内容都会成功更新。使用块来始终处理您的上下文也更好,即使会发生意外的异常。记录器将负责将错误写入另一个线程中的数据库,而不会降低程序的速度。也许你可以尝试NLog,我听说它比log4net更好(=更容易配置/使用),但我仍然需要自己尝试一下。

答案 1 :(得分:1)

如果您的数据库包含多个数据库模式,并且您希望将每个上下文作为单独的自包含区域处理,则为单个数据库提供多个上下文可能很有用。如果是这种情况,你的代码/要求就不清楚了。

如果您正在使用的表位于同一个数据库和相同的架构,然后我看不出你使用两个DbContexts的原因。即使您有验证错误或异常,您仍然可以使用相同的上下文保存到日志表中。

如果您尝试记录错误和/或其他相关信息,为什么不使用log4net进行日志记录?

修改

在我看来,日志记录应该与您的正常交易无关,因此您不必考虑这种情况。话虽这么说,在一个事务中你可以保存和记录,但如果有异常也会记录。除非我遗漏了某些内容,否则我仍然不需要2个DBContexts。

请查看以下内容,了解有关交易的一些指导。

https://msdn.microsoft.com/en-us/data/dn456843.aspx

答案 2 :(得分:0)

有一些问题。

  1. 如果我们在数据输入方面遇到异常(如果任何状态不受影响,我们可以继续运行)。但是如果我们在登录时遇到异常,我们就不会处理?

  2. 我们的业务逻辑在做什么?如果我们得到错误的json数据,我们的业务逻辑应检查并处理它。

    好吧,让我们说json是有效的,它传递业务逻辑。我们在db上使用varchar(20)有字符串字段,但数据有25个字符。那么我们的模型验证是做什么的呢?

    你应该在上层处理这些事情。

  3. 违反了单一责任。此方法应该只有一个责任,即将实体保存到db。它也不应该对记录负责。你应该在另一个班级实现它。

    因此,您的问题就出现了。你试图给这个方法两个可靠性。然后你尝试选择我需要的1个dbcontext或2个dbcontexts。如果您遵循单一责任,则不会出现此问题。

  4. 您应该实施记录器服务。您的课程不应该知道或关心记录器服务如何处理它。您可以将其保存到数据库,文件或云,如loggly。此外,您的记录器服务不应与其他类共享相同的上下文。

答案 3 :(得分:-2)

Entity Framework 5代码首次迁移只能管理每个物理数据库实例的单个DbContext。 Entity Framework 6代码首次迁移能够管理每个物理数据库实例的多个DbContext。

查看非常好的例子:

http://www.dotnet-tricks.com/Tutorial/entityframework/2VOa140214-Entity-Framework-6-Code-First-Migrations-with-Multiple-Data-Contexts.html