在Entity Framework中运行db.SaveChanges时,是否可以知道哪个函数引发了错误?

时间:2018-06-05 23:49:26

标签: c# entity-framework linq

我们希望将错误存储在数据库表中,以便在项目投入生产时找到出错的地方。我们希望捕获运行db.SaveChanges()时发生的错误。我们无法在生产中运行调试器,因此这是我们能够保存错误的答案。

到目前为止,我有这个:

public override int SaveChanges()
{
    try
    {
        return base.SaveChanges();
    }
    catch (DbEntityValidationException e)
    {
        var errorMessages = e.EntityValidationErrors
                .SelectMany(x => x.ValidationErrors)
                .Select(x => x.ErrorMessage);

        // Join the list to a single string.
        var fullErrorMessage = string.Join("; ", errorMessages);

        // Combine the original exception message with the new one.
        var exceptionMessage = string.Concat(e.Message, " The validation errors are: ", fullErrorMessage);

        // Throw a new DbEntityValidationException with the improved exception message.
        throw new DbEntityValidationException(exceptionMessage, e.EntityValidationErrors);
    }
    catch (DbUpdateException ex)
    {
        Exception realerror = ex;

        while (realerror.InnerException != null)
            realerror = realerror.InnerException;

        Console.WriteLine(realerror.ToString());
        throw ex;
    }
}

我正在尝试这样的事情,以便在SaveChanges()运行时捕获错误,就像它在一个地方一样。有没有办法知道哪个函数称为SaveChanges(),所以我可以将其保存在数据库中,以便我们可以看到它失败的位置或至少它被调用的行号?

我知道我可以为每个函数添加一个try-catch并捕获它并使用它有错误的函数以这种方式保存它,但我希望能够将它放在一个位置简单。

1 个答案:

答案 0 :(得分:1)

您需要Caller Information

如果您想要调用方法的方法名称,声明此方法的文件和行号,请​​执行以下操作:

public void SaveChanges(string message,  
    [System.Runtime.CompilerServices.CallerMemberName] string callerMethod = "",  
    [System.Runtime.CompilerServices.CallerFilePath] string sourceFile = "",  
    [System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0)  
{
    try
    {
        db.SaveChanges();
    }  
    catch (...)
    {
         // here you can use callerMethod, sourceFile, lineNumber
         // as string in your diagnostic message
    }
}  

用法:

using (var dbContext = new MyDbContext(...))
{
     ...
     dbContext.SaveChanges(); // all parameters are optional!
}

您必须为每个可选参数指定显式默认值。您不能将Caller Info属性应用于未指定为可选参数。

“来电者信息”属性不会使参数成为可选参数。相反,它们会影响省略参数时传入的默认值。

在编译时,调用者信息值作为文字发送到中间语言(IL)。与异常的StackTrace属性的结果不同,结果不受混淆的影响。

在极少数情况下,您不需要默认值,您可以明确地命名它们:

void ChangeCity(string city)
{
    ...
    DbContext.SaveChanges($"{nameof(ChangeCity)} where city = {city}");
}