是否可以在linq2sql中使用F#中的局部变量?

时间:2011-02-24 12:48:29

标签: linq-to-sql f#

Linq示例

<@ seq {for a in db.ArchiveAnalogs do
            for d in db.Deltas do
                let ack = ref false
                for ac in db.Acks do
                    if a.Date > ac.StartDate && a.Date < ac.EndDate then
                        ack := true
                yield
                    if a.ID = d.ID && a.Value > d.DeltaLimit then
                        Some(a.Date, d.AboveMessage, !ack)
                    elif a.ID = d.ID && a.Value < d.DeltaLimit then 
                        Some(a.Date, d.BelowMessage, !ack)
                    else None }
@> |> query |> Seq.choose id |> Array.ofSeq

错误讯息:

The following construct was used in query but is not recognised by the F#-to-LINQ query translator:
Sequential (Call (None,
                  Void op_ColonEquals[Boolean](Microsoft.FSharp.Core.FSharpRef`1[System.Boolean], Boolean),
                  [Call (None,
                         Microsoft.FSharp.Core.FSharpRef`1[System.Boolean] Ref[Boolean](Boolean),
                         [Value (false)]), Value (true)]),
            Call (None,
                  System.Collections.Generic.IEnumerable`1[Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.DateTime,System.String,System.Boolean]]] Empty[FSharpOption`1](),
                  []))
This is not a valid query expression. Check the specification of permitted queries and consider moving some of the query out of the quotation

2 个答案:

答案 0 :(得分:2)

不,不可能做你想做的事。 LINQ to SQL以&#34;表达式树&#34;的形式启用查询。要对数据库运行。 F#包装器将F#引用转换为与语言无关的.NET表达式树,然后将其提供给标准的LINQ to SQL机制。您尝试做的事情有两个问题:

  1. 表达式树仅支持一组有限的操作,而在.NET 3.5中,这不包括赋值。因此,即使F#引用可以包含对局部变量的赋值,query运算符也无法将其转换为.NET表达式树。

  2. 即使赋值可以在表达式树中表达,它们如何通过LINQ to SQL基础结构转换为SQL查询? LINQ to SQL背后的主要思想是确保将查询编译为SQL并在数据库上运行,但没有明显的方法将逻辑转换为数据库查询。

答案 1 :(得分:1)

只是提供有关错误消息的一些详细信息 - 您实际上可以在LINQ to SQL计算中使用let绑定。问题是你正在使用命令式构造和表达式命令式排序。

您的查询包含类似的内容(其中body是一个返回unit的表达式):

for v in e1 do
  body
yield e3

这是不允许的,因为LINQ to SQL只能包含只能包含单个表达式的C#表达式树 - 为了表示这一点,我们需要对语句的支持(但这在数据库中没有意义世界)。

要删除该语句,F#转换器会将其转换为某些内容(非常粗略地):

Special.Sequence
  (fun () -> for v in e1 do body) 
  (fun () -> e3)

现在它只是一个表达式(Sequence方法存在于F#库中的某个位置,因此您可以使用LINQ编译F#引用并动态运行它们),但是LINQ to SQL转换器无法理解{ {1}}并且无法处理它。