我想在执行之前重写LINQ表达式的某些部分.而且我在将重写器注入正确的位置时遇到了问题(实际上是这样).
查看实体框架源(在反射器中)它最终归结为IQueryProvider.ExecuteEF中的哪一个通过ObjectContext提供internal IQueryProvider Provider { get; }属性与表达式耦合.
所以我创建了一个包装器类(实现IQueryProvider),在调用Execute时执行Expression重写,然后将其传递给原始的Provider.
问题是,背后的领域Provider是private ObjectQueryProvider _queryProvider;.这ObjectQueryProvider 是一个内部密封类,这意味着不可能创建一个提供添加重写的子类.
因此,由于非常紧密耦合的ObjectContext,这种方法让我陷入了死胡同.
如何解决这个问题呢?我看错了方向吗?有没有办法让自己注意到这个ObjectQueryProvider?
更新:虽然提供的解决方案在您使用存储库模式"包装"ObjectContext时都能正常工作,但是允许直接使用ObjectContext生成的子类的解决方案将更可取.因此保持与Dynamic Data脚手架兼容.
正如这里所讨论的以及无数更多:我想知道是否有任何方法可以继承/扩展/ ...实体框架4.1将自定义方法转换为SQL.
我正在尝试实现一个与linq2entities一起使用的扩展方法.我最初假设如果我的扩展方法接受并返回了一个IQueryable,并且只要我的表达式只使用了受支持的方法,那么它就可以正常工作.我遇到了很多麻烦,所以作为最后的手段,我复制了一个我知道工作的现有.NET扩展方法(FirstOrDefault)并简单地重命名它.看起来它会根据方法返回的表达式来评估"无法转换为商店表达式"验证,而不是方法本身的名称.
var prs = db.People.Where(p => p.PersonKey == 15).Select(p =>
new
{
id = p.PersonKey,
name1 = p.PersonHistories.AsQueryable().AsOf().Name
}
).ToList();
Run Code Online (Sandbox Code Playgroud)
我的扩展方法,它只是我重命名的FirstOrDefault的副本:
public static TSource AsOf<TSource>(this IQueryable<TSource> source)
{
return source.Provider.Execute<TSource>(Expression.Call(null, ((MethodInfo)MethodBase.GetCurrentMethod()).MakeGenericMethod(new Type[] { typeof(TSource) }), new Expression[] { source.Expression }));
}
Run Code Online (Sandbox Code Playgroud)
错误:
LINQ to Entities does not recognize the method
'Models.PersonHistory AsOf[PersonHistory](System.Linq.IQueryable`1[Models.PersonHistory])'
method, and this method cannot be translated into a store expression.
Run Code Online (Sandbox Code Playgroud)
如何实现Linq2Entities支持的IQueryable扩展方法?
我真正想要的AsOf(source,DateTime asOf)就是这样source.FirstOrDefault<IHistory>(s => s.EndDate > asOf && asOf >= s.StartDate ),但我不知道如何实现这一点,以便linq2entities支持它.
LINQKIT:这是我用linqkit想出来的,我希望不知怎的,我可以把它变成更可重用的东西:
Expression<Func<PersonHistory, …Run Code Online (Sandbox Code Playgroud) 在linq to Entities中,我们需要一个类似"sql like"的方法.我们已经为IQueryable实现了我们自己的扩展方法,因为包含的方法对我们不起作用,因为它不接受像'%a%b%'这样的模式
创建的代码是:
private const char WildcardCharacter = '%';
public static IQueryable<TSource> WhereLike<TSource>(this IQueryable<TSource> _source, Expression<Func<TSource, string>> _valueSelector, string _textSearch)
{
if (_valueSelector == null)
{
throw new ArgumentNullException("valueSelector");
}
return _source.Where(BuildLikeExpressionWithWildcards(_valueSelector, _textSearch));
}
private static Expression<Func<TSource, bool>> BuildLikeExpressionWithWildcards<TSource>(Expression<Func<TSource, string>> _valueSelector, string _textToSearch)
{
var method = GetPatIndexMethod();
var body = Expression.Call(method, Expression.Constant(WildcardCharacter + _textToSearch + WildcardCharacter), _valueSelector.Body);
var parameter = _valueSelector.Parameters.Single();
UnaryExpression expressionConvert = Expression.Convert(Expression.Constant(0), typeof(int?));
return Expression.Lambda<Func<TSource, bool>> (Expression.GreaterThan(body, expressionConvert), parameter);
}
private static MethodInfo GetPatIndexMethod() …Run Code Online (Sandbox Code Playgroud)