我有以下LINQ-to-Entities查询,用于检索与给定日期(dte
)的日期部分匹配的记录:
Dim qry = entities.Works.Where(Function(w) w.JobID = RecordID And
SqlFunctions.DatePart("y", w.FromDate) = SqlFunctions.DatePart("y", dte) And
SqlFunctions.DatePart("m", w.FromDate) = SqlFunctions.DatePart("m", dte) And
SqlFunctions.DatePart("d", w.FromDate) = SqlFunctions.DatePart("d", dte))
我想重用这个表达式,先写下这样的东西:
Public SqlDateEquals As System.Linq.Expressions
.Expression(Of Func(Of DateTime, DateTime, Boolean)) = Function(dte1, dte2)
SqlFunctions.DatePart("y", dte1) = SqlFunctions.DatePart("y", dte2) And
SqlFunctions.DatePart("m", dte1) = SqlFunctions.DatePart("m", dte2) And
SqlFunctions.DatePart("d", dte1) = SqlFunctions.DatePart("d", dte2)
然后,在其他查询中:
Dim qry = entities.Works.Where(Function(w) w.JobID =
RecordID And SqlDateEquals(w.FromDate, dte))
我的理解是LINQ-to-Entities解析传递给.Where
的表达式,它应该能够将SqlFunctions.DatePart
识别为表达式的一部分。因此,包含SqlFunctions.DatePart
的表达式仍然可以解析为它们的等效SQL。
我该怎么做?
答案 0 :(得分:1)
您看到的问题与SqlFunctions.DatePart
无关;相反,这是因为你不能以你尝试的方式组合你的两个表达。
像这样编写表达式实际上并不像您期望的那样简单。 lambda表达式语法是一种不支持组合表达式的简写;你必须使用Expression
上的静态方法。
幸运的是,对您的案例有一种更简单的方法:
更新:使用Expression
的静态“构建器”方法添加了完成此操作的示例代码。
Imports System.ComponentModel.DataAnnotations
Imports System.Data.Entity
Imports System.Linq.Expressions
Imports System.Data.Objects.SqlClient
Imports System.Reflection
Class Entity
<Key> Public Property Key As Integer
Public Property P As String
End Class
Class Context
Inherits DbContext
Public Property Entities As DbSet(Of Entity)
End Class
Module Module1
Sub Main()
Dim expression1 As Expression(Of Func(Of Entity, Boolean)) = Function(e) e.P > "m"
Dim ctx As Context = New Context()
Dim query = From e In ctx.Entities
Where e.P < "p"
Select e
' Example 1. The easy way: chaining two Where clauses together.
' This works because q.Where(A AND B) is the same as q.Where(A).Where(B)
Dim q2 = query.Where(expression1)
Console.WriteLine(q2.ToString())
' Now the harder method.
Dim expression2 As Expression(Of Func(Of Entity, Boolean)) = Function(e) e.P < "p"
' Reproduce the above using static builder methods.
' Get an expression for our single parameter.
Dim parameter As ParameterExpression = Expression.Parameter(GetType(Entity))
' Get an expression for accessing its P property.
Dim pProperty = Expression.Property(parameter, "P")
' Get a MethodInfo for the string comparison method.
Dim compareMethod As MethodInfo = (From m In GetType(String).GetMethods()
Where m.Name = "Compare" AndAlso m.GetParameters().Count() = 2 AndAlso m.ReturnType = GetType(Integer)
Select m).First()
' Generate our combined lambda.
Dim combinedExpression = CType(
Expression.Lambda(
Expression.Or(
Expression.GreaterThan(Expression.Call(compareMethod, pProperty, Expression.Constant("p")), Expression.Constant(0)),
Expression.LessThan(Expression.Call(compareMethod, pProperty, Expression.Constant("m")), Expression.Constant(0))),
parameter),
Expression(Of Func(Of Entity, Boolean)))
Dim combinedQuery = ctx.Entities.Where(combinedExpression)
Console.WriteLine(combinedQuery.ToString())
Console.Read()
End Sub
End Module
上述示例中的第一个表达式的工作原理是.Where(A AND B)
在逻辑上与.Where(A).Where(B)
相同。如上面的示例代码所示,EF正确地为此生成了很好的SQL代码。
上面代码输出的第二个表达式很多更复杂。它展示了如何在代码中构建表达式。在这里,因为我们进行了OR
操作,所以我们无法使用链接Where()
调用的技巧。
有关问题及其解决方案的精彩讨论,请参阅this article。
答案 1 :(得分:0)
使用EntityFunctions.TruncateTime:
Dim datePart = dte.Date
Dim qry = entities.Works.Where(Function(w) w.JobID = RecordID And _
TruncateTime(w.FromDate) = datePart)
注意:我意识到这不能回答这个问题,但确实解决了这个问题。