Filter All Queries (Trying to Achieve Soft Delete)

Filter all queries (trying to achieve soft delete)

Can't test the exact API, but the general approach would be to create a constrained generic method and call it via reflection:

public static class EFFilterExtensions
{
public static void SetSoftDeleteFilter(this ModelBuilder modelBuilder, Type entityType)
{
SetSoftDeleteFilterMethod.MakeGenericMethod(entityType)
.Invoke(null, new object[] { modelBuilder });
}

static readonly MethodInfo SetSoftDeleteFilterMethod = typeof(EFFilterExtensions)
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Single(t => t.IsGenericMethod && t.Name == "SetSoftDeleteFilter");

public static void SetSoftDeleteFilter<TEntity>(this ModelBuilder modelBuilder)
where TEntity : class, ISoftDeleteModel
{
modelBuilder.Entity<TEntity>().HasQueryFilter(x => !x.IsDeleted);
}
}

Now you can use something like this inside your OnModelCreating:

foreach (var type in modelBuilder.Model.GetEntityTypes())
{
if (typeof(ISoftDeleteModel).IsAssignableFrom(type.ClrType))
modelBuilder.SetSoftDeleteFilter(type.ClrType);
}

How to code in django soft delete or how to filter query in model?

Generally speaking, a custom manager is a good candidate for this task. The example would be:

from core.managers import ABCManager

class ABC(models.Model):
soft_delete = models.BooleanField(default=False)
# other fields
objects = ABCManager()
# active = ABCActiveManager()

store your managers in the separated file (managers.py):

from django.db.models import Manager

class ABCManager(Manager):
def get_queryset(self):
query = super().get_queryset()

query = query.filter(soft_delete=False)

return query

But this is a global solution, objects will always return instances with soft_delete=False. In case (most likely) when you also need to get deleted objects you could instead of overriding default (objects) manager name your own differently.


Also, you could solve the issue with the class method:

class ABC(models.Model):
soft_delete = models.BooleanField(default=False)

@classmethod
def active_records(cls):
return cls.objects.filter(soft_delete=False)

And call it on the class level like so:

ABC.active_records()
# <QuerySet [<ABC: ABC object (1)>, <ABC: ABC object (2)>]>

It's quite hard to suggest a solution because it really depends on how you're going to use it later.

Global Query Filter only for GET method

If you want to work with a DbSet that has a query filter, but need to access objects that have been filtered, you can use the IgnoreQueryFilters method, for example:

var deletedUsers = context.Employees
.IgnoreQueryFilters()
.Where(e => e.IsDeleted);


Related Topics



Leave a reply



Submit