Soft Delete the childs of my entity

c# entity-framework-core

Question

  • I have a sample with sampleItems.
  • I delete a sampleItem from the list of sampleItems in sample.
  • I save the DBContext.

I want to SoftDelete the sampleItem.

My code:

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

When I get the entity from the DB:

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

In MyDbContext I have:

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

So I expected to have the SampleItem I deleted with an entryState to Deleted, but not, the entryState is set to Modified. But When I look in the database after operations done, the sampleItem is deleted.

How can I softDelete the sampleItem in this situation?


EDIT:

I read here: https://github.com/aspnet/EntityFrameworkCore/issues/11240, the answer from ajcvickers that I could use "entry.Navigations".

I notice that SampleItem has NavigationEntries, all SampleItems are in it except the one I deleted.

So maybe we can imagine a linq function to the one who are not in the list? I m trying with no success currently. Is there someone who knows how to do it?

        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();

EDIT 2

Here: https://github.com/aspnet/EntityFrameworkCore/issues/3815, I found a way to disabled Cascade delete.

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

Now I have an error when I execute the SaveChanges:

"The association between entities 'Sample' and 'SampleItem' with the key value '{Id: 1c41c336-b75b-4f6b-6057-08d5f3d981ae}' has been severed but the relationship is either marked as 'Required' or is implicitly required because the foreign key is not nullable. If the dependent/child entity should be deleted when a required relationship is severed, then setup the relationship to use cascade deletes."

(more details about Cascade configuration: https://docs.microsoft.com/en-us/ef/core/saving/cascade-delete)

Which is normal. Now I need to find to disable the delete of the SampleItem and enable the SoftDelete.

Do you have an idea?

1
1
7/28/2018 3:02:46 AM

Popular Answer

You are probably solved this already BUT remove the sample.SampleItems.RemoveAt(index); and replace with:

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

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

Then on your 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;
                        }
                    }
                }
1
9/22/2019 5:09:46 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow