3

我有以下 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。

我怎样才能做到这一点?

4

2 回答 2

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()调用的技巧。

有关该问题及其解决方案的精彩讨论,请参阅本文

于 2013-06-07T16:53:39.053 回答
0

使用EntityFunctions.TruncateTime

Dim datePart = dte.Date
Dim qry = entities.Works.Where(Function(w) w.JobID = RecordID And _
    TruncateTime(w.FromDate) = datePart)

注意:我意识到这并不能回答问题,但确实可以解决问题。

于 2013-08-22T19:31:00.633 回答