简体   繁体   English

实体框架核心:如何为 DbSet Find 方法忽略查询过滤器

[英]Entity Framework Core: How to IgnoreQueryFilters for DbSet Find method

I am using Global Query Filters but do not want to apply it on DbSet .Find method.我正在使用全局查询过滤器,但不想将其应用于 DbSet .Find方法。 I can not use .IgnoreQueryFilters because it returns IQueryable .我不能使用.IgnoreQueryFilters因为它返回IQueryable Also I do not want use .FirstOrDefault due to performance reasons.由于性能原因,我也不想使用.FirstOrDefault

Help is appreciated.帮助表示赞赏。

You can create 'Find' extension method for IDbSet<T> where you can "simulate" original Find method lookup flow.您可以为IDbSet<T>创建“Find”扩展方法,您可以在其中“模拟”原始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);
}

I didn't test it, but might work just fine.我没有测试它,但可能工作得很好。

In case you have some common table key convention you can even go for more generic extension method.如果您有一些通用的表键约定,您甚至可以使用更通用的扩展方法。

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

Hope it helps.希望能帮助到你。

I created more generic approach based on dropoutcoder solution.我基于dropoutcoder解决方案创建了更通用的方法。 It does not require that DbSet has primary key with strict Id name.它不要求 DbSet 具有带有严格Id名称的主键。 It still has only one key restriction but it suits me well.它仍然只有一个键限制,但它很适合我。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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