我在带有Code First的.NET 4.5应用程序中使用Entity Framework 6.1.3,并在Oracle数据库服务器上使用手工制作的表模式。大多数事情都很好。对于新函数,SaveChanges
中会抛出以下异常:
操作失败:无法更改关系,因为一个或多个外键属性不可为空。当对关系进行更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。
堆栈追踪:
它没有说明这个问题。它找不到我帮助我。 SQL日志是空的,所以我猜想在尝试联系数据库之前,本地EF已经检测到问题。
我的问题是:我该如何调试这个东西?哪个对象具有哪个值但不应该具有哪些外键的详细信息?是否有可用于Entity Framework的跟踪日志,其中包含有关已执行操作的内部数据?
这种情况太复杂了,无法在此展示,所以请不要问它。我想帮助自己解决这个问题,我只需要对此有所帮助。
答案 0 :(得分:2)
您可以登录SQL
using (var context = new BlogContext())
{
context.Database.Log = Console.Write;
// Your code here...
}
您甚至可以制作这样的自定义日志格式化程序
public class OneLineFormatter : DatabaseLogFormatter
{
public OneLineFormatter(DbContext context, Action<string> writeAction)
: base(context, writeAction)
{
}
public override void LogCommand<TResult>(
DbCommand command, DbCommandInterceptionContext<TResult> interceptionContext)
{
Write(string.Format(
"Context '{0}' is executing command '{1}'{2}",
Context.GetType().Name,
command.CommandText.Replace(Environment.NewLine, ""),
Environment.NewLine));
}
public override void LogResult<TResult>(
DbCommand command, DbCommandInterceptionContext<TResult> interceptionContext)
{
}
}
您可以使用自己的日志格式化程序截取确切的异常,前提是该异常是'DbEntityValidationException'
public class MyExcpetionCommandInterceptor : IDbCommandInterceptor
{
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);
}
private void LogIfNonAsync<TResult>(
DbCommand command, DbCommandInterceptionContext<TResult> interceptionContext)
{
if (!interceptionContext.IsAsync)
{
Logger.Warn("Non-async command used: {0}", command.CommandText);
}
}
private void LogIfError<TResult>(
DbCommand command, DbCommandInterceptionContext<TResult> interceptionContext)
{
if (interceptionContext.Exception.GetType() == typeof(DbEntityValidationException) || typeof(DbEntityValidationException).IsAssignableFrom(interceptionContext.Exception.GetType()) )
{
Logger.Error("Command {0} failed with exception {1}",
command.CommandText, interceptionContext.Exception);
}
}
}
中有一篇不错的文章
答案 1 :(得分:0)
您可以覆盖DBContext的SaveChanges方法,并查看所有属性的更新/删除/修改,它将最小化您需要检查错误的列表。我只需要删除/分离的内容,但您可以根据需要修改 .where 。
public override int SaveChanges()
{
try
{
var debug = false;
if (debug)
{
var modifiedEntities = ChangeTracker.Entries()
.Where(p => p.State == EntityState.Deleted || p.State == EntityState.Detached).ToList();
foreach (var change in modifiedEntities)
{
var entityName = change.Entity.GetType().Name;
System.Diagnostics.Debug.WriteLine(string.Format("Entity {0}", entityName));
}
}
return base.SaveChanges();
}
catch (DbEntityValidationException e)
{
foreach (var eve in e.EntityValidationErrors)
{
Debug.WriteLine("Error while Save Changes:");
Debug.WriteLine("Entity {0} has the following validation errors:", eve.Entry.Entity.GetType().Name);
foreach (var ve in eve.ValidationErrors)
{
Debug.WriteLine("Property:{0}, Error: {1}",
ve.PropertyName, ve.ErrorMessage);
}
}
throw;
}
catch (Exception)
{
throw;
}
}