开发者

is it possible to work with local variables inside linq2sql for F#?

开发者 https://www.devze.com 2023-02-12 23:41 出处:网络
Linq example <@ seq {for a in db.ArchiveAnalogs do for d in db.Deltas do let ack = ref false for ac in db.Acks do

Linq example

<@ 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

Error message :

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


No, it's not possible to do what you want. LINQ to SQL enables queries in the form of "expression trees" to be run against a database. The F# wrapper converts F# quotations into language-agnostic .NET expression trees, which are then fed to the standard LINQ to SQL machinery. There are two issues with what you're trying to do:

  1. Expression trees only support a limited set of operations, and in .NET 3.5 this does not include assignments. Therefore, even though an F# quotation can contain assignments to local variables, there's no way for the query operator to translate this into a .NET expression tree.

  2. Even if assignments could be expressed in an expression tree, how would they be translated to a SQL query by the LINQ to SQL infrastructure? The main idea behind LINQ to SQL is to ensure that the query is compiled to SQL and run on the database, but there's no obvious way to translate your logic into a database query.


Just to give some details about the error message - You can actually use let binding inside the LINQ to SQL computations. The problem is that you're using imperative construct and imperative sequencing of expressions.

Your query contains something like this (where body is some expression that returns unit):

for v in e1 do
  body
yield e3

This is not allowed, because LINQ to SQL can only contain C# expression trees that can contain just a single expression - to represent this, we'd need the support for statements (but that doesn't quite make sense in the database world).

To remove the statement, the F# translator converts this to something (very roughly) like:

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

Now it is just a single expression (The Sequence method lives somewhere in F# libraries, so that you can compile F# quotations using LINQ and run them dynamically), but the LINQ to SQL translator doesn't understand Sequence and cannot deal with it.

0

精彩评论

暂无评论...
验证码 换一张
取 消