如何记录我的实体错误详细

时间:2014-12-20 01:20:21

标签: entity-framework logging reflection

我想存储我的实体类'属性'如果发生任何错误,则为额外值。这样做的最佳做法是什么?我想,通过反射获取值并将它们写入数据库是一个很好的解决方案但是然后它创建了另一个问题。我怎样才能达到所有价值,包括收藏品'值,换句话说,儿童对象'值。我试图通过使用反射达到但我坚持了,失败了。如果我的解决方案有误,我愿意接受任何合适的解决方案,建议:)

例如:

public class Author : BaseEntity
{

    /// <summary>
    /// Gets or sets a value indicating the author's name
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// Gets or sets a value indicating the author's surname
    /// </summary>
    public string Surname { get; set; }

    /// <summary>
    /// Gets or sets a value indicating the author's birthdate
    /// </summary>
    public DateTime BirthDate { get; set; }

    /// <summary>
    /// Gets or sets a value indicating the author's death of date
    /// </summary>
    public DateTime DeathDate { get; set; }

    /// <summary>
    /// Gets or sets a value indicating rating entity
    /// </summary>
    public virtual AuthorRating Rating { get; set; }

    /// <summary>
    /// Gets or sets a value indicating idenitifier of the author's nationality
    /// </summary>
    public int NationalityId { get; set; }

    /// <summary>
    /// Gets or sets a value indicating the author's nationality
    /// </summary>
    public virtual Nation Nationality { get; set; }

    /// <summary>
    /// Gets or sets the collection of votes
    /// </summary>
    public virtual ICollection<AuthorVote> HavingVotes { get; set; }

    /// <summary>
    /// Gets or sets the collection of quotes which he/she said
    /// </summary>
    public virtual ICollection<Quote> OwnQuotes { get; set; }

    /// <summary>
    /// Gets or sets the collection of favourited rows by user
    /// </summary>
    public virtual ICollection<UserFavouriteAuthor> Favouriteds { get; set; }

}

例如,如何使用反射递归地获取Author.Qutes.QuoteVotes类及其值及其子项?

2 个答案:

答案 0 :(得分:4)

要处理DbEntityValidationException,请在try catch块中包围与DbContext相关的代码,并将其用于例外

public void AppendValidationErrors(Exception e)
{
    DbEntityValidationException ex = e is DbEntityValidationException ?
        e as DbEntityValidationException : null ;

    if (ex == null) { log.Info(e); return; }

    foreach (var eve in ex.EntityValidationErrors)
    {
        log.Info(string.Format("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
            eve.Entry.Entity.GetType().Name, eve.Entry.State));

        foreach (var ve in eve.ValidationErrors)
        {
            log.Info(string.Format("- Property: \"{0}\", Error: \"{1}\"",
                ve.PropertyName, ve.ErrorMessage));
        }
    }
}

要获取属性值,可以使用EF的DbPropertyValues

    public static void PrintValues(DbPropertyValues values) 
    { 
        foreach (var propertyName in values.PropertyNames) 
        { 
            Console.WriteLine("Property {0} has value {1}", 
                              propertyName, values[propertyName]); 
        } 
    }

   PrintValues(context.Entry(User).GetDatabaseValues()); 

答案 1 :(得分:1)

如果要记录数据库的错误行为,可以从实体框架的IDbCommandInterceptor开始,并拦截数据库的警告和错误。

/// <summary>
/// The supported logging types
/// </summary>
public enum LogTarget { Log4net, Console, File };


public class DbCommandLogger : IDbCommandInterceptor
{
   #region Appender Definitions

    /// <summary>
    /// Assign a method to append an error
    /// </summary>
    /// <param name="error">The error to append</param>
    private Action<string> appendError;

    /// <summary>
    /// Assign a method to append a warning
    /// </summary>
    /// <param name="warning">The warning to append</param>
    private Action<string> appendWarning;

    #endregion


    #region Fields

    private static readonly log4net.ILog log = log4net.LogManager.GetLogger("WarningsAndErrorsAppender");

    #endregion


    #region Construct and Setup

    public DbCommandLogger(LogTarget logTarget, string path = "db")
    {
        SetupAppenders(logTarget, path);
    }


    /// <summary>
    /// Setups appenders according to the specified log target. It can only be accessed via the constructor
    /// </summary>
    /// <param name="logTarget">The log target</param>
    /// <param name="path">The file path. Leave empty if you don't want to specify a path</param>
    private void SetupAppenders(LogTarget logTarget, string path = "db")
    {
        switch (logTarget)
        {
            case LogTarget.Console:
                appendError = Console.Write;
                appendWarning = Console.Write;
                break;
            case LogTarget.File:
                appendError = File.CreateText(path + ".Errors.log").WriteLine;
                appendWarning = File.CreateText(path + ".Warning.log").WriteLine;
                break;
            case LogTarget.Log4net:
                appendWarning = x => log.Warn(x);
                appendError = x => log.Error(x);
                break;
            default:
                appendWarning = x => { };
                appendError = x => { };
                break;
        }
    }

    #endregion


    #region Queries

    public void NonQueryExecuting(
        DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
        LogIfNonAsync(command, interceptionContext);
    }

    public void NonQueryExecuted(
        DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
        LogIfError(command, interceptionContext);
    }   

    public void ReaderExecuting(
        DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        LogIfNonAsync(command, interceptionContext);
    }

    public void ReaderExecuted(
        DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        LogIfError(command, interceptionContext);
    }

    public void ScalarExecuting(
        DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
        LogIfNonAsync(command, interceptionContext);
    }

    public void ScalarExecuted(
        DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
        LogIfError(command, interceptionContext);
    }

    #endregion


    #region Log Commands

    /// <summary>
    /// Log a warning for any command that is executed non-asynchronously
    /// </summary>
    /// <typeparam name="TResult"></typeparam>
    /// <param name="command">The command being executed.</param>
    /// <param name="interceptionContext">Contextual information associated with the call.</param>
    private void LogIfNonAsync<TResult>(
        DbCommand command, DbCommandInterceptionContext<TResult> interceptionContext)
    {
        if (!interceptionContext.IsAsync)
        {
            appendWarning(String.Format("Non-async command used: {0}", command.CommandText));
         }
    }

    /// <summary>
    /// Log an error for any command that throws when executed
    /// </summary>
    /// <typeparam name="TResult"></typeparam>
    /// <param name="command">The command being executed.</param>
    /// <param name="interceptionContext">Contextual information associated with the call.</param>
    private void LogIfError<TResult>(
        DbCommand command, DbCommandInterceptionContext<TResult> interceptionContext)
    {
        if (interceptionContext.Exception != null)
        {
            appendError(String.Format("Command {0} failed with exception {1}",
                 command.CommandText, interceptionContext.Exception));
        }
    }

    #endregion


    #region Helpers

    [MethodImpl(MethodImplOptions.NoInlining)]
    public string GetCurrentMethod()
    {
        StackTrace st = new StackTrace();
        StackFrame sf = st.GetFrame(1);

        return sf.GetMethod().Name;
    }

    #endregion

}

然后,您可以使用DbContext扩展方法注册拦截器

/// <summary>
/// Logs erroneous database behavior. Set the appender method via the log4net.config file located in the project's target folder
/// </summary>
/// <param name="context">The DbContext object that's being tracked</param>
public static void LogWarningsAndErrors(this DbContext context,LogTarget logTarget)
{
    string path = FolderExists("LogFiles") ? "LogFiles\\" + context.ToString() :context.ToString();

    DbInterception.Add(new DbCommandLogger(logTarget, path));
}

最后,您可以通过DbContext轻松记录错误,如下所示:

context.LogWarningsAndErros(LogTarget.Log4Net);