删除嵌套集合中的实体

时间:2020-03-10 20:04:54

标签: c# entity-framework-6

更新实体时,在实体方法中删除了多个子集合的情况下,我无法将更改保存到数据库中。 我从RemoveSpecificMiddleLvlEntities实体调用HighLvlEntity方法。一些孩子被删除。从EfRepository通过Update方法进行更新时,引发以下错误。 我是否必须通过Delete方法手动收集集合中的所有子级? 我认为我真的不了解基本的Entity Framework 6概念之一吗?想要让我知道哪些实体不在任何存储库或服务中委派了哪些实体。

谢谢。

错误:System.InvalidOperationException:“操作失败: 无法更改关系,因为其中一个或多个 外键属性不可为空。当对 关系时,相关外键属性设置为空值。 如果外键不支持空值,则建立新关系 必须定义,必须为外键属性分配另一个 非null值,否则必须删除不相关的对象。”

我的简化实体:

public class Base
{
    public Guid Id { get; set; }

    public Base()
    {
        Id = Guid.NewGuid();
    }
}
public class HighLvlEntity : Base
{
    public HighLvlEntity(string name)
    {
        Name = name;
    }
    public string Name { get; set; }
    public ICollection<MiddleLvlEntity> middleLvlEntities { get; set; } = new List<MiddleLvlEntity>();

    public void RemoveSpecificMiddleLvlEntities(ICollection<MiddleLvlEntity> middleLvlEntitiesOfCriteria)
    {
        foreach (var MiddleLvlEntity in middleLvlEntitiesOfCriteria)
        {
            var foundmiddleLvlEntity = middleLvlEntities.Where(p => p.Testcriteria == MiddleLvlEntity.Testcriteria).First();
            middleLvlEntities.Remove(foundmiddleLvlEntity);
            {
            }
        }
    }
}
public class MiddleLvlEntity : Base
{
    public MiddleLvlEntity(string testcriteria)
    {
        Testcriteria = testcriteria;
    }
    public ICollection<LowLvlTwo> LowLvlTwos { get; set; } = new List<LowLvlTwo>();
    public ICollection<LowLvlOne> LowLvlOnes { get; set; } = new List<LowLvlOne>();
    public string Testcriteria { get; set; }
    public HighLvlEntity HighLvlEntity { get; set; }
    public Guid HighlvlEntityId { get; set; }
}
public class LowLvlOne : Base
{
    public LowLvlOne(DateTime date)
    {
        Date = date;
    }
    public DateTime Date { get; set; }
    public Guid middleLvlEntityId { get; set; }
    public MiddleLvlEntity MiddleLvlEntity { get; set; }
}
public class LowLvlTwo : Base
{
    public LowLvlTwo(DateTime date)
    {
        Date = date;
    }
    public DateTime Date { get; set; }
    public Guid middleLvlEntityId { get; set; }
    public MiddleLvlEntity MiddleLvlEntity { get; set; }
}

EfRepository:

public class EfRepository<T> : IRepository<T> where T : Base
{
    protected readonly Context _dbContext;

    public EfRepository(Context dbContext)
    {
        _dbContext = dbContext;
    }

    public void Update(T entity)
    {
        _dbContext.Entry(entity).State = EntitieState.Modified;

        _dbContext.SaveChanges();
    }

    public void Delete(T entity)
    {
        _dbContext.Set<T>().Remove(entity);
        _dbContext.SaveChanges();
    }
}

更新: This seems to be same problem。 然后我的问题是,我到底该如何构建它能正常工作的应用程序。我有一个包含实体,接口和服务的核心项目。具有实现并连接到实体框架的基础结构项目。因此,我在Core项目中的实体不了解dbcontext和如何从子集合中删除项目。我是否必须摆脱这种想法,而是要在实体本身中实现业务逻辑,以便在核心项目中使用服务接口并在基础结构项目中使用服务实现?

1 个答案:

答案 0 :(得分:0)

不幸的是,当人们想要正确处理所谓的孤立记录时,对于EF6来说,似乎(大多数)不可能完全不了解实体。

How to remove child one to many related records in EF code first database?

那么,还有哪些选择呢?

咬紧牙关,使实体(至少)具有持久性意识。

显然不是您想要的,但是如果我们

  1. 以类似于DDD的方式重塑我们的实体,就像更大的面向操作/任务的聚合而不是普通实体
  2. 明智地抽象持久性

它可能不会像现在看起来那样糟糕

在SaveChanges(或其他)上添加一些巧妙的自定义孤儿处理

类似https://stackoverflow.com/a/42048505/3745022

或者尝试从identifying relationships中获得最大收益-对他们来说,孤儿删除是可行的。

请勿删除实体

除非确实需要删除这些实体(域限制,数据库大小/性能,GDPR ...),否则您可以将它们标记为已删除或将它们添加到某些DeletedParent中。

嗯,我知道这可能不可行,这会使系统的某些方面变得更加复杂且容易出错,但是在许多情况下,不删除实体会非常有利(能够回滚操作,生成历史数据等)

使用EF Core(2.2?)

EF Core似乎支持正确的orphan removal

尽管您无法使用{.3} {.3}},但仍可以尝试EF Core 2.2,因为它也应该支持孤立删除。

是的,EF和EF Core之间存在一些差异,但是对于一个似乎处于早期阶段的项目而言,它们并不是无法克服的。