2014-12-20 2 views
2

Я хочу сохранить значения свойств объектов сущности как дополнительные, если произошла какая-либо ошибка. Каковы наилучшие методы для этого? Я думал, что получение ценностей путем отражения и запись их в базу данных - это хорошее решение, но затем оно создает другой вопрос. Как я могу достичь всех значений, включая значения Collections, другими словами, значения дочерних объектов. Я пытался достичь, используя отражение, но я застрял, не смог. Если мое решение не так, я открыт для любых подходящих решений, предложения :)Как регистрировать ошибки моего объекта в деталях

Например:

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 и их ценности и их дети рекурсивно, используя отражение?

ответ

4

Чтобы справиться с DbEntityValidationException , объедините свой связанный с DbContext код в блоке try catch и используйте его для вашего исключения

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)); 
     } 
    } 
} 

Чтобы получить значения свойств, вы можете использовать DbPropertyValues ​​EF в

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()); 
+0

Это не проблема. Просто, кроме того, я хочу зарегистрировать объект entity со своими свойствами. Например, при выполнении любых операций CRUD произошла ошибка, и я хочу зарегистрировать связанный объект, такой как User-UserName: «Test User», Surname: «Sur», bla bla. Я уже сделал ваше решение, но я хочу сделать немного больше для более подробного ведения журнала ошибок. – ArnesTwin

+0

Я обновил свой ответ, посмотрю, подходит ли он вам – GMich

+0

Да, просто вещь .. Он работал, как я хочу. Хорошее решение – ArnesTwin

1

Если вы хотите зарегистрировать ошибочное поведение вашей базы данных, вы можете наследовать от Entity Framework 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); 
+0

Это хорошее решение, но у меня есть проблема с этим. DbContext throw s DbEntityValidationException перед выполнением запроса, в SaveChanges(), поэтому становится обязательным, чтобы я должен войти в систему, чтобы попытаться поймать блоги в репозиториях. Поэтому решение не приносит мне пользы. – ArnesTwin

Смежные вопросы