【问题标题】:The relationship could not be changed because one or more of the foreign-key properties is non-nullable. (2)无法更改关系,因为一个或多个外键属性不可为空。 (2)
【发布时间】:2016-03-04 14:23:32
【问题描述】:

我在 .NET 4.5 应用程序中使用 Entity Framework 6.1.3,并在 Oracle 数据库服务器上使用 Code First 和手工制作的表模式。大多数事情都很好。对于新函数,SaveChanges 中会引发以下异常:

操作失败:无法更改关系,因为一个或多个外键属性不可为空。当对关系进行更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。

堆栈跟踪:

  • System.Data.Entity.Core.Objects.ObjectContext.PrepareToSaveChanges(System.Data.Entity.Core.Objects.SaveOptions)
  • System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(System.Data.Entity.Core.Objects.SaveOptions, bool)
  • System.Data.Entity.Internal.InternalContext.SaveChanges()
  • (我的代码)

它没有说明问题。它没有帮助我找到它。 SQL 日志是空的,所以我猜 EF 甚至在尝试访问数据库之前就已在本地检测到问题。

我的问题是:我该如何调试这个东西?关于哪个对象中的哪个外键具有哪个值但不应该有的详细信息在哪里?是否有可用于 Entity Framework 的跟踪日志,其中包含有关已完成操作的内部数据?

这里的情况太复杂了,所以请不要在这里展示它。我想帮助自己解决这个问题,我只需要帮助。

【问题讨论】:

  • 如果您在调试模式下使用Linq to Entities,您可以查看生成的SQL。请发布失败的代码,因为我们无法为您提供这些信息。
  • 同时发布您的模型类
  • 跟进詹姆斯的建议。 blogs.msdn.com/b/mpeder/archive/2014/06/16/… 如果您查看 SQL(听起来会非常复杂),您应该能够看到一些 FK 被设置为 NULL
  • 没有SQL,那个日志已经就位,没有写任何东西。该错误发生在我所看到的甚至生成 SQL 之前。模型类对此太长并且可能是机密的。由于我不知道哪些课程受到影响,所以我不知道该发布什么。您不想调试我的整个应用程序。我只需要知道在哪里可以找到 EF 丢失的信息。
  • 阅读 EF 源代码,它似乎来自“概念上为空”的东西。有人知道这是什么意思吗?

标签: c# .net entity-framework


【解决方案1】:

您可以覆盖 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;
            }
        }

【讨论】:

    【解决方案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);
            }
        }
    }
    

    微软Logging and intercepting database operations有一篇很好的文章

    【讨论】:

    • 无论我 4 年前的项目是什么,我都已经放弃了,所以我无法再验证这个答案了。
    猜你喜欢
    • 2015-12-16
    • 2013-10-19
    • 2014-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多