我正在使用全局查询过滤器,但不希望将其应用于DbSet .Find
方法。我无法使用.IgnoreQueryFilters
,因为它返回了IQueryable
。另外,由于performance的原因,我也不想使用.FirstOrDefault
。
感谢您的帮助。
答案 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;
}
}