软删除我实体的子代

时间:2018-07-27 15:28:33

标签: c# entity-framework-core

  • 我有一个带有sampleItems的样本。
  • 我从样本中的sampleItems列表中删除了sampleItem。
  • 我保存了DBContext。

我要删除样品项。

我的代码:

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,所有SampleItem都在其中,除了我删除的那个。

那么也许我们可以想象一个不在列表中的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,我找到了一种禁用Cascade删除的方法。

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。

你有个主意吗?

1 个答案:

答案 0 :(得分:1)

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

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

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

然后在您的替代保存更改上:

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;
                        }
                    }
                }