C# 关系处于已删除状态

C# 关系处于已删除状态,c#,entity-framework,ef-code-first,entity-framework-5,C#,Entity Framework,Ef Code First,Entity Framework 5,当我尝试清除集合(调用.clear)时,会出现以下异常: 保存未公开其关系的外键属性的实体时出错。EntityEntries属性将返回null,因为无法将单个实体标识为异常源。通过在实体类型中公开外键属性,可以更轻松地在保存时处理异常。有关详细信息,请参见InnerException 内部例外是: 来自“用户可用性”关联的关系处于“已删除”状态。给定多重性约束,相应的“用户可用性目标”也必须处于“已删除”状态 用户看起来像这样: .... ICollection<Availability&

当我尝试清除集合(调用
.clear
)时,会出现以下异常:

保存未公开其关系的外键属性的实体时出错。EntityEntries属性将返回null,因为无法将单个实体标识为异常源。通过在实体类型中公开外键属性,可以更轻松地在保存时处理异常。有关详细信息,请参见InnerException

内部例外是:

来自“用户可用性”关联的关系处于“已删除”状态。给定多重性约束,相应的“用户可用性目标”也必须处于“已删除”状态

用户看起来像这样:

....
ICollection<Availability> Availability { get; set; }
int ID { get; set; }
User User { get; set; }
DateTime Start { get; set;
DateTime End { get; set; }
配置如下:

HasMany(x => x.Availability).WithRequired(x => x.User);
HasRequired(x => x.User).WithMany(x => x.Availability);
导致问题的代码是:

user.Availability.Clear();

我已经研究过其他替代方法,比如使用DbSet删除项目,但我觉得我的代码不会那么干净。有没有办法通过清除集合来实现这一点?

我所知道的使其工作的唯一方法是将关系定义为一个集合。需要将外键从
可用性
引入到
用户
作为外键引入您的型号中

public int ID { get; set; }
public int UserID { get; set; }
public User User { get; set; }
…并使其成为主键的一部分:

modelBuilder.Entity<Availability>()
    .HasKey(a => new { a.ID, a.UserID });
modelBuilder.Entity()
.HasKey(a=>new{a.ID,a.UserID});
您可以扩展映射以包含此外键(只是为了明确起见,它不是必需的,因为EF将按照约定识别它):

modelBuilder.Entity()
.HasRequired(a=>a.User)
.WithMany(u=>u.Availability)
.HasForeignKey(a=>a.UserID);
(顺便说一句:您只需要从一侧配置关系。您的问题中不需要同时具有这两个映射。)


现在可以使用
user.Availability.clear()清除集合
可用性
实体将从数据库中删除。

有一个技巧。您可以在不使用特殊数据库集的情况下删除实体:

(this.dataContext as IObjectContextAdapter).ObjectContext.DeleteObject(entity);

在清除可用性集合中的每个项目之前,对其执行此操作。这种方法不需要“识别关系”。

如果有人在使用SQLite时遇到同样的问题:

不幸的是,接受的答案不适用于SQLite,因为SQLite不支持复合键的自动递增

您还可以在数据库上下文中重写SaveChanges()方法以删除子项:

//// Long Version
//var localChilds = this.SubCategories.Local.ToList();
//var deletedChilds = localChilds.Where(w => w.Category == null).ToList();
//foreach(var child in deletedChilds) {
//   this.SubCategories.Remove(child);
//}

// Short in LINQ
this.SubCategories.Local
    .Where(w => w.Category == null).ToList()
    .ForEach(fe => this.SubCategories.Remove(fe));
#endregion

请参阅伟大的博客文章作为我的来源(不幸是用德语写的)。

感谢您发布这篇文章!当我在子对象上运行更新时,由于FK属性和navigation属性,我在同一列上得到多个SET语句。只有一个SET语句有什么诀窍吗?@Thomas:我不知道。SQL生成基本上掌握在EF手中,很难控制。我真的很惊讶,同一个FK列有两个集合表达式。EF应该知道FK属性和nav。属性表示相同的FK列和关系。是否确定示例正确?您有modelBuilder.Entity().HasRequired(x=>x.User)。。。这不应该是Entity()的配置吗?我尝试了此配置,但收到一条错误消息:“操作失败:无法更改关系,因为一个或多个外键属性不可为null…”。如果外键可以为空,这可能适用于多个方面?解决了我的问题,但我得到了一个“当identity_insert设置为OFF时无法为表xxx中的identity列插入显式值”。解决方案是将属性
[DatabaseGenerated(DatabaseGeneratedOption.identity)]
添加到原始ID列on(在本例中)可用性<正如德里克评论的那样,代码>确实应该是
//// Long Version
//var localChilds = this.SubCategories.Local.ToList();
//var deletedChilds = localChilds.Where(w => w.Category == null).ToList();
//foreach(var child in deletedChilds) {
//   this.SubCategories.Remove(child);
//}

// Short in LINQ
this.SubCategories.Local
    .Where(w => w.Category == null).ToList()
    .ForEach(fe => this.SubCategories.Remove(fe));
#endregion