简体   繁体   中英

Can I make Global Query Filters in Entity Framework 6? by OnModelCreating?

I try to make a global query. I know that this is possible in EF Core 2.0 however I need to do it using EF 6.

I try to do something like this in EF 6: (IsDeleted is a property in my Class Cliente as boolean)

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Client>().HasQueryFilter(x => x.IsDeleted= false);
}

I will appreciate your help, thank you!

What I believe is that you want to implement soft-delete in your application. To apply a global query filter you can follow this approach too.

first of all, install System.linq.Dynamic Library using NuGet.

Then create one extension Method like:

public static IQueryable<T> WhereDeleted<T>(this IQueryable<T> source)
{
    return source.Where("IsDeleted== false"); 
}

and then you can call other methods like this:

var client = db.Client.Include("whatever you need")
                      .WhereDeleted().Where(c => c.Age < 30);

Unfortunately, EF6 doesn't support query filters.

Here is an approach you could use to implement similar behaviour.

Note: This approach doesn't use Dependency injection (DI), however it should be simple enough to modify it to make use of DI.

//Marker interface
public interface IQueryFilter
{

}

public interface IQueryFilter<T> : IQueryFilter
    where T : class
{
    Expression<Func<T, bool>> Expression { get; }
}

public static class QueryableExtensions
{
    private static readonly Lazy<IEnumerable<Type>> _queryFilterTypes = new Lazy<IEnumerable<Type>>(GetQueryFilterTypes);

    public static IQueryable<T> Filter<T>(this IQueryable<T> queryable)
        where T : class
    {
        foreach (Type type in _queryFilterTypes.Value)
        {
            IQueryFilter<T> queryFilter = Create<T>(type);

            if (queryFilter?.Expression != null)
            {
                queryable = queryable.Where(queryFilter.Expression);
            }
        }

        return queryable;
    }

    private static IEnumerable<Type> GetQueryFilterTypes()
    {
        return Assembly.GetExecutingAssembly() //the assembly where you will have your query filters
            .GetTypes()
            .Where(x => typeof(IQueryFilter).IsAssignableFrom(x)
                && !x.IsAbstract)
            .ToArray();
    }

    private static IQueryFilter<T> Create<T>(Type type)
        where T : class
    {
        IQueryFilter<T> filter = null;

        if (typeof(IQueryFilter<T>).IsAssignableFrom(type))
        {
            filter = CreateImpl(type);
        }
        else if (type.IsGenericType)
        {
            Type entityType = typeof(T);
                
            TypeInfo typeInfo = type.GetTypeInfo();

            Type genericParameter = typeInfo.GenericTypeParameters.SingleOrDefault();
                
            if (genericParameter != null)
            {
                foreach (var constraint in genericParameter.GetGenericParameterConstraints())
                {
                    if (!constraint.IsAssignableFrom(entityType))
                    {
                        return null;
                    }
                }
            }

            filter = CreateImpl(type.MakeGenericType(entityType));
        }

        return filter;

        IQueryFilter<T> CreateImpl(Type t)
        {
            IQueryFilter<T> result = null;

            ConstructorInfo constructor = t.GetConstructor(Array.Empty<Type>());

            if (constructor != null)
            {
                result = (IQueryFilter<T>)constructor.Invoke(Array.Empty<object>());
            }

            return result;
        }
    }
 }

Example interface:

public interface ISoftDeletable
{
    bool IsDeletable { get; }
}

Example entity:

public class Person : ISoftDeletable
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public bool IsDeleted { get; set; }
}

Example IQueryFilter<T> implementation

public class NotDeletedQueryFilter<T> : IQueryFilter<T>
    where T : class, ISoftDeletable
{
    public Expression<Func<T, bool>> Expression { get; } = x => !x.IsDeleted;
}

Example usage. (The DbContext has a DbSet<Person> named People )

var peoples = await dbContext.People
    .Filter()
    .ToListAsync();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM