我正在尝试创建一个通用类,用于编写实体框架 (5) 的查询。
我让它工作了,唯一的问题是该值作为查询的常量而不是作为参数注入。这减少了 EF 缓存查询并稍后重用它的可能性。
这是我到目前为止所得到的。
public class MinDateFilter<T> : IFilter<T> where T : class
{
private readonly Expression<Func<T, bool>> _predicate;
public MinDateCandidateFilter(Expression<Func<T, DateTime>> propertySelector, DateTime from)
{
from = from.Date.AddDays(-1);
from = new DateTime(from.Year, from.Month, from.Day, 23, 59, 59, 999);
Expression value = Expression.Constant(from, typeof(DateTime));
//ParameterExpression variable = Expression.Variable(typeof(DateTime), "value");
MemberExpression memberExpression = (MemberExpression)propertySelector.Body;
ParameterExpression parameter = Expression.Parameter(typeof(T), "item");
Expression exp = Expression.MakeMemberAccess(parameter, memberExpression.Member);
Expression operation = Expression.GreaterThan(exp, value);
//Expression operation = Expression.GreaterThan(exp, variable);
_predicate = Expression.Lambda<Func<T, bool>>(operation, parameter);
}
public IQueryable<T> Filter(IQueryable<T> items)
{
return items.Where(_predicate);
}
}
这个类有两种使用方式:
通过子分类它:
public class MinCreationDateCandidateFilter : MinDateFilter<Candidate>
{
public MinCreationDateCandidateFilter(DateTime @from) : base(c => c.CreationDate, @from) {}
}
或者简单地通过实例化它:
var filter = new MinDateFilter<Entities.Transition>(t => t.Date, from.Value);
这是我迄今为止所实现的目标:
SELECT
[Extent1].[Id] AS [Id]
-- Other fields
FROM [dbo].[Candidates] AS [Extent1]
WHERE [Extent1].[CreationDate] > convert(datetime2, '1982-12-09 23:59:59.9990000', 121)
而不是
SELECT
[Extent1].[Id] AS [Id]
-- Other fields
FROM [dbo].[Candidates] AS [Extent1]
WHERE [Extent1].[CreationDate] > @p__linq__0
如果我取消注释这两行注释并注释上面的两行,则会收到一条错误消息,指出参数“值”未绑定。
我希望我提供了所有有用的细节:)
当参数作为
ConstantExpression
传递时,如下所示:
Expression.Constant(myString)
...它将在结果查询上生成固定的常量符号:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Bar] AS [Bar],
FROM [dbo].[Foo] AS [Extent1]
WHERE [Extent1].[Bar] = "Some text"
如果我们使用像Expression Tree Visualizer这样的工具来分析像
(f => f.Bar == myString))
这样的表达式,我们会发现参数实际上是一个MemberExpression
。
因此,为了在结果查询中使用参数而不是字符串常量,我们必须传递诸如对象属性之类的东西,或更方便的匿名类型:
Expression.Property(
Expression.Constant(new { Value = myString }),
"Value"
)
通过这种方式,我们传递刚刚创建的对象的属性,并且表达式树获得可重用的
MemberExpression
,从而产生针对缓存进行优化的 CommandText
:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Bar] AS [Bar],
FROM [dbo].[Foo] AS [Extent1]
WHERE [Extent1].[Bar] = @p__linq__0