Sto cercando di implementare Soft Delete in un'applicazione .NET Core 1.1. * Web, supportata da Entity Framework Core 1.1. *. Sto usando SQL Server come mio DB.
La migrazione a .NET core 2. * non è un'opzione al momento.
Dopo aver letto libri, tuts e 3ds, ho implementato questa funzione usando una colonna Discriminator
. La procedura di cancellazione sembra funzionare come previsto. Quello che non va è il recupero dei dati: le entità cancellate sono ancora mostrate nei risultati della query EF.
Ecco un codice C #. Terrò le cose il più semplice possibile
Le interfacce:
// Soft deletion interface
public intercace ISoftDeletable
{}
// Another interface for some shadow properties
public interface IEntity
{}
La classe base:
public abstract class Entity : IEntity, ISoftDeletable
{
public int MyBaseProp { get; set; }
}
Una delle mie classi derivate:
public class MyDerivedEntity: Entity
{
public string Name { get; set; }
public IList<MyChildEntity> Children { get; set; }
}
public class MyChildEntity: Entity
{
public string MyChildProp { get; set; }
}
Il contesto
public class MyContext: DbContext
{
public MyContext(DbContextOptions<MyContext> options)
: base(options)
{ }
public DbSet<MyDerivedEntity> EntitiesToUse { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
foreach (var entity in builder.Model.GetEntityTypes())
{
if (typeof(IEntity).IsAssignableFrom(entity.ClrType))
{
builder.Entity(entity.ClrType).Property<string>("MyShadowProperty");
}
if (typeof(ISoftDeletable).IsAssignableFrom(entity.ClrType))
{
// Discriminator column
builder.Entity(entity.ClrType).HasDiscriminator("IsDeleted", typeof(bool)).HasValue(false);
// Shadow Property
builder.Entity(entity.ClrType).Property(typeof(bool), "IsDeleted").IsRequired(true).HasDefaultValue(false);
builder.Entity(entity.ClrType).Property(typeof(bool), "IsDeleted").Metadata.IsReadOnlyAfterSave = false;
}
}
// Other model configurations
base.OnModelCreating(builder);
}
// SaveChangesAsync are almost the same
public override int SaveChanges()
{
AuditEntities();
return base.SaveChanges();
}
private void AuditEntities()
{
foreach (EntityEntry<IEntity> entry in ChangeTracker.Entries<IEntity>())
{
// do something with MyShadowProperty...
}
foreach (EntityEntry<ISoftDeletable> entry in changeTracker.Entries<ISoftDeletable>().Where(w => w.State == EntityState.Deleted))
{
// Set the entity as Softly Deleted
entry.Property("IsDeleted").CurrentValue = true;
// Ensure the entity state is modified to prevend hard deletion
entry.State = EntityState.Modified;
}
}
}
Tutto funziona come previsto, tranne il recupero dei dati. Ecco una chiamata di esempio:
var results = await _context.EntitiesToUse.Include(e => e.SomeChildEntity).AsNoTracking();
Mi aspetto che i risultati includano solo myDerivedEntities disponibili con .IsDeleted == false
. Il problema è che le mie entità cancellate non sono filtrate. Perché?
Per favore, cosa c'è di sbagliato nel mio codice? Mi sto perdendo qualcosa?
Grazie mille a tutti!
Entity Framework Core 2.0 supporta il filtro di query globale
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ISoftDeletable>().HasQueryFilter(e => !e.IsDeleted);
base.OnModelCreating(modelBuilder);
}
Puoi trovare maggiori informazioni ed esempi qui
Vi raccomando il filtro di query globale EF Core incorporato ma, in alcune situazioni, anche Entity Framework Plus può essere d'aiuto.
Disclaimer : sono il proprietario di questo progetto
EF + Filtro query consente di filtrare DbSet a livello globale e per istanza.
// using Z.EntityFramework.Plus; // Don't forget to include this.
var ctx = new EntitiesContext();
ctx.Filter<IUser>(q => q.Where(x => !x.IsSystemUser ));
// SELECT * FROM Customers WHERE IsSystemUser = FALSE
var list = ctx.Customers.ToList();
Wiki: EF + Filtro query
EDIT: Rispondi alla sotto-domanda
Per favore, la tua libreria è compatibile con EF Core 1.1
Sì, dovrebbe essere compatibile con .NET Standard 1.3