【问题标题】:Soft Delete the childs of my entity软删除我的实体的孩子
【发布时间】:2019-09-22 13:09:46
【问题描述】:
  • 我有一个带有 sampleItems 的样品。
  • 我从 sample 中的 sampleItems 列表中删除了一个 sampleItem。
  • 我保存了 DBContext。

我想软删除 sampleItem。

我的代码:

public class Entity: {
        public Guid Id { get; set; }
        public bool IsDeleted { get; set; }
}

public class Sample : Entity{
        public string Text { get; set; }
        public List<SampleItem> SampleItems { get; set; } = new List<SampleItem>();
}

public class SampleItem :Entity{
        public string Text { get; set; }
        public virtual Sample Sample { get; set; }
}

当我从数据库中获取实体时:

var sample = context.Samples.First(s=>s.Id == myId);
sample.SampleItems.RemoveAt(index);
context.SaveChanges();

在 MyDbContext 我有:

public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
{
    foreach (var entry in ChangeTracker.Entries())
    {
        switch (entry.State)
        {
            case EntityState.Added:
                //Do stuff
                break;

            case EntityState.Modified:
                //Do stuff
                break;

            case EntityState.Deleted:
                if (entry.Entity is Entity entity)
                {
                    entry.State = EntityState.Unchanged;
                    entity.IsDeleted = true;
                }
                break;
        }
    }

    return base.SaveChangesAsync(cancellationToken);
}

所以我希望我删除的 SampleItem 的 entryState 为 Deleted,但不是,entryState 设置为 Modified。但是当我在操作完成后查看数据库时,sampleItem 被删除了。

在这种情况下如何软删除 sampleItem?


编辑:

我在这里读到:https://github.com/aspnet/EntityFrameworkCore/issues/11240,来自 ajcvickers 的答案是我可以使用“entry.Navigations”。

我注意到 SampleItem 有 NavigationEntries,所有 SampleItems 都在其中,除了我删除的那个。

所以也许我们可以为不在列表中的人想象一个 linq 函数?我目前正在尝试没有成功。有人知道怎么做吗?

        var x = ChangeTracker.Entries()
            .Where(e => !e.Navigations
                .Where(n => !n.Metadata.IsDependentToPrincipal())
                .Where(n => n is CollectionEntry)
                .Select(n => n as CollectionEntry)
                .SelectMany(n => n.CurrentValue.Cast<object>())
                .Select(Entry)
                .Contains(e)
            )
            .ToList();

编辑 2

这里:https://github.com/aspnet/EntityFrameworkCore/issues/3815,我找到了禁用级联删除的方法。

foreach (var relationship in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
{
    relationship.DeleteBehavior = DeleteBehavior.Restrict;
}

现在执行 SaveChanges 时出现错误:

"实体 'Sample' 和 'SampleItem' 之间的关联与 键值“{Id: 1c41c336-b75b-4f6b-6057-08d5f3d981ae}”已 已被切断,但该关系要么标记为“必需”,要么 隐式需要,因为外键不可为空。如果 当需要关系时,应删除依赖/子实体 被切断,然后设置关系以使用级联删除。”

(有关级联配置的更多详细信息:https://docs.microsoft.com/en-us/ef/core/saving/cascade-delete)

这是正常的。现在我需要找到禁用删除 SampleItem 并启用 SoftDelete。

你有什么想法吗?

【问题讨论】:

  • 我会从一开始就将软删除作为定期更新处理。毕竟,它是更新。对象图中的实体状态错综复杂地相互关联。你不想篡改它们。我从不理解这些将删除重定向到更新的狡猾解决方案。它总是会产生不可预知的副作用。
  • 有一天,实体框架团队将默认启用软删除,我希望 ;)。但目前,是的,狡猾的解决方案是一种方法。

标签: c# entity-framework-core


【解决方案1】:

您可能已经解决了这个问题,但删除 sample.SampleItems.RemoveAt(index); 并替换为:

// Do the soft delete
db.IsSoftDelete = true;
db.Entry(activity).State = EntityState.Modified;

db.UserId = userId;
await db.SaveChangesAsync();

然后在您的 Override SaveChanges 上:

public bool IsSoftDelete { get; set; }

public override int SaveChanges()
{
   ...
// Modified State
                var modified = this.ChangeTracker.Entries()
                            .Where(t => t.State == EntityState.Modified)
                            .Select(t => t.Entity)
                            .ToArray();

                foreach (var entity in modified)
                {
                    if (entity is ITrack)
                    {
                        var track = entity as ITrack;
                        Entry(track).Property(x => x.CreatedDate).IsModified = false;
                        Entry(track).Property(x => x.CreatedBy).IsModified = false;
                        track.ModifiedDate = DateTime.UtcNow;
                        track.ModifiedBy = UserId;

                        if (IsSoftDelete)
                        {
                            track.IsDeleted = true;
                            track.DeletedDate = DateTime.UtcNow;
                            track.DeletedBy = UserId;
                        }
                    }
                }

【讨论】:

  • 我从来没有找到解决方案......目前,我真的很忙,但如果可以的话,我会尝试你的解决方案(我希望很快)。感谢您的帮助:)
猜你喜欢
  • 2015-10-10
  • 2022-08-13
  • 2019-07-09
  • 2021-07-22
  • 2016-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-18
相关资源
最近更新 更多