繁体   English   中英

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

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

我正在使用全局查询过滤器,但不想将其应用于 DbSet .Find方法。 我不能使用.IgnoreQueryFilters因为它返回IQueryable 由于性能原因,我也不想使用.FirstOrDefault

帮助表示赞赏。

您可以为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);
}

我没有测试它,但可能工作得很好。

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

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

希望能帮助到你。

我基于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;
    }
}

暂无
暂无

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

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