首页 > 解决方案 > 软删除我的实体的孩子

问题描述

我想软删除 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,我可以使用“entry.Navigations”的 ajcvickers 的答案。

我注意到 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

解决方案


您可能已经解决了这个问题,但删除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;
                        }
                    }
                }

推荐阅读