保存不会为其关系公开外键属性的实体时发生错误

我首先在Entity Framework 4.1代码中有一个简单的代码:

 PasmISOContext db = new PasmISOContext(); var user = new User(); user.CreationDate = DateTime.Now; user.LastActivityDate = DateTime.Now; user.LastLoginDate = DateTime.Now; db.Users.Add(user); db.SaveChanges(); user.Avatar = new Avatar() { Link = new Uri("http://myUrl/%2E%2E/%2E%2E") }; db.SaveChanges(); db.Users.Add(new User() { Avatar = new Avatar() { Link = new Uri("http://myUrl/%2E%2E/%2E%2E") } }); db.SaveChanges(); 

问题是我得到一个错误

保存不会为其关系公开外键属性的实体时发生错误。 EntityEntries属性将返回null,因为单个实体不能被识别为exception的来源。 通过在实体types中公开外键属性,可以更轻松地处理exception。 有关详细信息,请参阅InnerException。

 db.Users.Add(new User() { Avatar = new Avatar() { Link = new Uri("http://myUrl/%2E%2E/%2E%2E") } }); db.SaveChanges(); 

我不明白为什么类似的操作起作用。 我的模型或者ef-code优先有什么问题吗?

 public class Avatar { [Key] public int Id { get; set; } [Required] public string LinkInString { get; set; } [NotMapped] public Uri Link { get { return new Uri(LinkInString); } set { LinkInString = value.AbsoluteUri; } } } public class User { [Key] public int Id { get; set; } public string UserName { get; set; } public string Email { get; set; } public string Password { get; set; } public Avatar Avatar { get; set; } public virtual ICollection<Question> Questions { get; set; } public virtual ICollection<Achievement> Achievements { get; set; } public DateTime CreationDate { get; set; } public DateTime LastLoginDate { get; set; } public DateTime LastActivityDate { get; set; } } 

对于那些仍然有这个错误,所有键都被正确定义的人来说,看看你的实体,并确保你不留下一个空值的date时间字段。

这个错误信息可能是由于任何原因引发的。 “InnerException”属性(或者它的InnerException,或者InnerException,等等)包含了问题的实际主要原因。

知道问题发生的位置当然是有用的 – 工作单元中的哪个对象导致了问题? exception消息通常会在'EntityEntries'属性中告诉你,但在这种情况下,出于某种原因,这是不能完成的。 这种“EntityEntries”属性为空的诊断复杂性显然是因为某些实体不公开其关系的外键属性。

即使OP由于未能初始化User的第二个实例的DateTime而得到错误,他们也会得到诊断复杂性 – 'EntityEntries'为空,并且是一个令人困惑的顶级消息…因为他们的实体之一不' t“公开外键属性”。 为了解决这个问题, Avatar应该有一个public virtual ICollection<User> Users { get; set; } public virtual ICollection<User> Users { get; set; } public virtual ICollection<User> Users { get; set; }属性定义。

该问题已通过添加FK属性得到解决。

在我的情况下,以下情况给了我同样的例外:

设想一个代码第一个EF模型,其中有一个具有Car实体集合的Garage实体。 我需要从车库中取出一辆车,所以我最终得到了这样的代码:

 garageEntity.Cars.Remove(carEntity); 

相反,它应该看起来像这样:

 context.Cars.Remove(carEntity); 

只针对可能有类似问题的其他人。 我有同样的错误,但出于不同的原因。 在其中一个子对象中,我将[Key]定义为对于不同的保存是相同的值。 我的一个愚蠢的错误,但错误信息并不会立即引发你的问题。

在我的情况下,由于EF已经错误地创build了迁移,所以引发了这种怀疑。 它错过了设置身份:真正的第二张桌子上。 因此,进入创build相关表的迁移,并检查是否错过了添加标识。

 CreateTable( "dbo.LogEmailAddressStats", c => new { Id = c.Int(nullable: false, identity: true), EmailAddress = c.String(), }) .PrimaryKey(t => t.Id); CreateTable( "dbo.LogEmailAddressStatsFails", c => new { Id = c.Int(nullable: false), // EF missed to set identity: true!! Timestamp = c.DateTime(nullable: false), }) .PrimaryKey(t => t.Id) .ForeignKey("dbo.LogEmailAddressStats", t => t.Id) .Index(t => t.Id); 

一个Id列应该有身份(即自动递增!),所以这必须是一个EF错误。

您可以手动添加身份与SQL直接到数据库,但我更喜欢使用entity framework。

如果你遇到同样的问题,我会看到两个简单的解决scheme

Alt 1

反向错误地创build的迁移与

 update-database -target:{insert the name of the previous migration} 

然后将身份:手动添加到迁移代码,然后再次更新数据库

Alt 2

您创build一个新的迁移,添加身份。 如果你没有改变模型,你运行

 add-migration identity_fix 

它会创build一个空的迁移。 然后加上这个

  public partial class identity_fix : DbMigration { public override void Up() { AlterColumn("dbo.LogEmailAddressStatsFails", "Id", c => c.Int(nullable: false, identity: true)); } public override void Down() { AlterColumn("dbo.LogEmailAddressStatsFails", "Id", c => c.Int(nullable: false)); } } 

这个问题也可能来自反向的关键声明。 如果您使用stream畅configuration关系,请确保左键和右键映射到正确的实体。

另一个答案:

我用这个:

 public List<EdiSegment> EdiSegments { get; set; } 

而不是这个:

 public virtual ICollection<EdiSegment> EdiSegments { get; set; } 

并得到了上面提到的错误信息。

我有同样的错误,在我的情况下,问题是,我添加了一个已经加载“AsNoTracking”的关系对象。 我不得不重新加载关系属性。

顺便说一句,有人build议使用“附加”关系已经存在的数据库,我还没有尝试过这个选项。

我也有同样的问题。 在我的情况下,这是由于date时间字段与空值。 我不得不通过一个值date时间,evrythings进展良好

在我的情况下,问题是我不正确地重命名列,所以迁移做了两列,一个名为“TeamId”和一个名为“TeamID”。 C#关心,SQL不。

这是另一个不同的情况。 一个查询被转换为一个列表,在做这个时,它通过构造函数创build了实体,以便在ToList()之后的linqexpression式中进行比较。 这创build了linqexpression式完成后进入已删除状态的实体。
然而! 有一个小的调整,在构造函数中创build了另一个实体,这样这个新实体就被链接到了一个被标记为已删除的实体。

一些代码来说明:

 query.Except(_context.MyEntitySetSet() .Include(b => b.SomeEntity) .Where(p => Condition) .ToList() // This right here calls the constructor for the remaining entities after the where .Where(p => p.Collection.First(b => Condition).Value == 0) .ToList(); 

MyEntity的构造函数:

 public partial class MyEntity { protected MyEntity() { // This makes the entities connected though, this instance of MyEntity will be deleted afterwards, the instance of MyEntityResult will not. MyEntityResult = new MyEntityResult(this); } } 

我的解决scheme是确保整个expression式在IQueryable中完成,以便不会创build任何对象。

我不完全确定这会帮助你的情况,因为我使用Fluent API来设置我的表,但是,据我所知,无论模式是使用数据注释(属性)设置的,或Fluent API(configuration)。

在EF(6.1.3)中似乎存在一个错误,因为在将数据库更新到下一个迁移时,它会省略模式的某些更改。 最快的路线是(在开发阶段)从数据库中删除所有的表,并再次从初始阶段开始迁移。

如果你已经在生产中,我find的最快的解决scheme是手动改变数据库中的模式,或者如果你想拥有对变化的版本控制,可以手动操作你的方法Up()Down()移民。