我得到这个错误时,我GetById()在一个实体,然后设置子实体的集合到我的新列表,来自MVC视图。

操作失败 关系是无法改变的 因为一个或多个外键 Properties是非空的。当一个 关系发生了变化 相关外键属性设置为 空值。如果外键是 不支持空值,新建 关系必须被定义 必须分配外键属性 另一个非空值或 必须删除不相关的对象。

我不太理解这句话:

这种关系无法改变 因为一个或多个外键 Properties是非空的。

我为什么要改变两个实体之间的关系?它应该在整个应用程序的生命周期内保持不变。

发生异常的代码只是简单地将集合中修改过的子类分配给现有的父类。这将有望满足取消子类,增加新的和修改。我本以为实体框架处理这个。

代码行可以提炼为:

var thisParent = _repo.GetById(1);
thisParent.ChildItems = modifiedParent.ChildItems();
_repo.Save();

当前回答

我也遇到了同样的问题,但我知道它在其他情况下也能正常工作,所以我把问题简化为:

parent.OtherRelatedItems.Clear();  //this worked OK on SaveChanges() - items were being deleted from DB
parent.ProblematicItems.Clear();   // this was causing the mentioned exception on SaveChanges()

OtherRelatedItems有一个复合主键(parentId +一些本地列),工作正常 probleaticitems有自己的单列主键,而parentId只是一个FK。这导致了Clear()之后的异常。

我所要做的就是使ParentId成为复合PK的一部分,以表明没有父元素就不能存在子元素。我使用DB-first模型,添加PK并将parentId列标记为EntityKey(因此,我必须在DB和EF中更新它-不确定EF单独是否足够)。

仔细想想,这是一个非常优雅的区别,EF使用它来决定没有父对象的子对象是否“有意义”(在这种情况下,Clear()不会删除它们并抛出异常,除非你将ParentId设置为其他/特殊的对象),或者-就像最初的问题一样-我们期望项一旦从父对象中删除就会删除。

其他回答

如果你正在使用自动绘图器,面临以下问题是一个很好的解决方案,它为我工作

https://www.codeproject.com/Articles/576393/Solutionplusto-aplus-Theplusoperationplusfailed

因为问题是我们正在映射空导航属性,我们实际上不需要在实体上更新它们,因为它们在契约上没有改变,我们需要在映射定义上忽略它们:

ForMember(dest => dest.RefundType, opt => opt.Ignore())

所以我的代码是这样的:

Mapper.CreateMap<MyDataContract, MyEntity>
ForMember(dest => dest.NavigationProperty1, opt => opt.Ignore())
ForMember(dest => dest.NavigationProperty2, opt => opt.Ignore())
.IgnoreAllNonExisting();

出现这个问题是因为我们试图删除父表,但仍然存在子表数据。 我们利用级联删除来解决这个问题。

在模型中创建dbcontext类中的方法。

 modelBuilder.Entity<Job>()
                .HasMany<JobSportsMapping>(C => C.JobSportsMappings)
                .WithRequired(C => C.Job)
                .HasForeignKey(C => C.JobId).WillCascadeOnDelete(true);
            modelBuilder.Entity<Sport>()
                .HasMany<JobSportsMapping>(C => C.JobSportsMappings)
                  .WithRequired(C => C.Sport)
                  .HasForeignKey(C => C.SportId).WillCascadeOnDelete(true);

之后,在我们的API调用中

var JobList = Context.Job                       
          .Include(x => x.JobSportsMappings)                                     .ToList();
Context.Job.RemoveRange(JobList);
Context.SaveChanges();

级联删除选项删除父表以及与父相关的子表,使用这个简单的代码。用这个简单的方法试试。

删除范围用于删除数据库中的记录列表 谢谢

我使用了Mosh的解决方案,但我不清楚如何在代码中正确地实现组合键。

这就是解决方案:

public class Holiday
{
    [Key, Column(Order = 0), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int HolidayId { get; set; }
    [Key, Column(Order = 1), ForeignKey("Location")]
    public LocationEnum LocationId { get; set; }

    public virtual Location Location { get; set; }

    public DateTime Date { get; set; }
    public string Name { get; set; }
}

我也遇到了同样的问题,但我知道它在其他情况下也能正常工作,所以我把问题简化为:

parent.OtherRelatedItems.Clear();  //this worked OK on SaveChanges() - items were being deleted from DB
parent.ProblematicItems.Clear();   // this was causing the mentioned exception on SaveChanges()

OtherRelatedItems有一个复合主键(parentId +一些本地列),工作正常 probleaticitems有自己的单列主键,而parentId只是一个FK。这导致了Clear()之后的异常。

我所要做的就是使ParentId成为复合PK的一部分,以表明没有父元素就不能存在子元素。我使用DB-first模型,添加PK并将parentId列标记为EntityKey(因此,我必须在DB和EF中更新它-不确定EF单独是否足够)。

仔细想想,这是一个非常优雅的区别,EF使用它来决定没有父对象的子对象是否“有意义”(在这种情况下,Clear()不会删除它们并抛出异常,除非你将ParentId设置为其他/特殊的对象),或者-就像最初的问题一样-我们期望项一旦从父对象中删除就会删除。

我也解决了我的问题与Mosh的答案,我认为PeterB的答案是有点,因为它使用枚举作为外键。请记住,在添加这段代码之后,您将需要添加一个新的迁移。

我也可以推荐这篇博客的其他解决方案:

http://www.kianryan.co.uk/2013/03/orphaned-child/

代码:

public class Child
{
    [Key, Column(Order = 0), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string Heading { get; set; }
    //Add other properties here.

    [Key, Column(Order = 1)]
    public int ParentId { get; set; }

    public virtual Parent Parent { get; set; }
}