实体框架核心:如何忽略DbSet查找方法的QueryFilters

时间:2020-03-09 16:31:42

标签: c# entity-framework-core

我正在使用全局查询过滤器,但不希望将其应用于DbSet .Find方法。我无法使用.IgnoreQueryFilters,因为它返回了IQueryable。另外,由于performance的原因,我也不想使用.FirstOrDefault

感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

您可以为IDbSet<T>创建“查找”扩展方法,在其中可以“模拟”原始的Find方法查找流程。

public static async Task<T> FindAsync<T>(this IDbSet<T> source, Expression<Func<TSource,bool>> predicate)
    where T : class, new()
{
    // parameters validation if needed

    return
        source.Local.SingleOrDefault(predicate)
        ?? await source.IgnoreQueryFilters().SingleOrDefaultAsync(predicate);//.ConfigureAwait(false);
}

我没有对其进行测试,但是可能效果很好。

如果您有一些通用的表键约定,甚至可以使用更通用的扩展方法。

public static async Task<T> FindAsync<T, TKey>(this IDbSet<T> source, TKey id)
    where T : class, new()
    where TKey : IEquatable<TKey>
{
    // parameters validation if needed

    return
        source.Local.SingleOrDefault(e => e.Id == id)
        ?? await source.IgnoreQueryFilters().SingleOrDefaultAsync(e => e.Id == id);//.ConfigureAwait(false);
}

希望有帮助。

答案 1 :(得分:0)

我基于 dropoutcoder 解决方案创建了更通用的方法。不需要DbSet具有严格的Id名称的主键。它仍然只有一个关键限制,但很适合我。

public static class DataContextProviderExtensions
{
    public static T FindWithIgnoreQueryFilters<T, TValue>(this DataContextProvider context, TValue id) where T : class, new()
    {
        var expr = GetByIdExpression<T, TValue>(context, id);

        return context.Set<T>().Local.SingleOrDefault(expr.Compile())
            ?? context.Set<T>().IgnoreQueryFilters().SingleOrDefault(expr);
    }

    private static Expression<Func<T, bool>> GetByIdExpression<T, TValue>(DataContextProvider context, TValue id) where T : class, new()
    {
        var keys = context.GetEntityKeys<T>().ToArray();
        if (keys.Length != 1)
            throw new Exception("GetByIdExpression works only with Entity which has one primary key column.");

        var param = Expression.Parameter(typeof(T), "p");
        var exp = Expression.Lambda<Func<T, bool>>(
            Expression.Equal(
                Expression.Property(param, keys[0]),
                ExpressionClosureFactory.GetField(id)
            ),
            param
        );
        return exp;
    }
}

internal class ExpressionClosureFactory
{
    public static MemberExpression GetField<TValue>(TValue value)
    {
        var closure = new ExpressionClosureField<TValue>
        {
            ValueProperty = value
        };

        return Expression.Field(Expression.Constant(closure), "ValueProperty");
    }

    class ExpressionClosureField<T>
    {
        public T ValueProperty;
    }
}