仅在不打印调试语句时实体框架种子方法出错

时间:2016-06-15 15:06:43

标签: c# entity-framework

在我们的Entity Framework 6种子方法中,我们将用户首选项设置为默认值。我们有很多问题让东西正常工作,所以我们开始将调试语句打印到文件中。但是,现在,如果我们删除调试行,就会出现异常。

以下是代码:

                // Get the preferences. 
                Preferences prefs = context.Preferences.FirstOrDefault(x => x.UserId == user.Id);

                using (StreamWriter write = new StreamWriter(@"C:\myFile.txt"))
                {
                    //foreach (PropertyInfo prop in prefs.GetType().GetProperties())
                    //    write.WriteLine($"{prop.Name} = {prop.GetValue(prefs)}");

                    prefs.ColumnIds = defaultColumnIds;
                    prefs.Columns = defaultColumns;
                    prefs.CategoriesOnYAxis = true;
                    prefs.TabHorizontal = true;
                    prefs.OnlyAssignedToUser = true;

                    context.SaveChanges();
                }

如果我们取消注释For循环,那么种子方法运行正常。在for循环注释掉后,我们得到以下异常:

  

保存不公开外键的实体时发生错误   他们关系的属性。 EntityEntries属性将   返回null,因为无法将单个实体标识为源   例外。可以在保存时处理异常   通过在实体类型中公开外键属性更容易。看到   InnerException以获取详细信息。

在此示例中,User对象是Preferences对象的1-1,而Preferences具有User表的外键。

我们甚至可以取出流编写器并将属性循环到控制台,只要该循环存在,种子方法就可以正常运行。一旦它消失,我们就会收到错误。

1 个答案:

答案 0 :(得分:1)

我猜这里可能会发生什么。我认为这是你的问题:

prefs.ColumnIds = defaultColumnIds; prefs.Columns = defaultColumns;

我认为这些是由数据库中的相同字段支持的?那么您是否设置了Column实体以及ColumnId主键?你不需要同时设置它们(虽然它应该工作)。

我敢打赌,如果删除prefs.Columns的作业(并省略调试代码),您的代码将开始工作。问题是defaultColumns。那里有什么?列实体 - 但是那些附加到当前DbContext的实体? (您的代码并未显示它们是如何形成的)

当您使用context.Preferences.FirstOrDefault(x => x.UserId == user.Id);获取首选项时,您要求EF为首选项实体,但默认情况下,EF不会获得预先加载导航属性(如列实体)。相反,如果你有一堆Column实体,但它们没有明确地附加到(或使用)当前的DbContext,那么EF会认为那些Columns是新的,并且这种关系可能不会以EF的方式映射可以插入新列(无论如何你都不想发生这种情况)。

当你的调试代码运行时,prefs.GetType().GetProperties()正在枚举Preference中的所有属性,我认为EF是延迟加载的。当您删除循环时,它不再枚举,因此所有首选项的导航属性都没有预先加载。

有几种方法可以解决这个问题:

  • 如果您确定运行Seed方法时所有defaultColumnIds已经在数据库中,那么只设置ColumnIds并将其称为一天。它会在执行查询时匹配数据库中的实体,只要预期的外键在那里就可以了。

  • 打开上下文后立即从上下文中获取defaultColumns,或者,如果您在代码中定义了它们,请在调用SaveChanges之前将它们附加到ChangeTracker。