is it possible to work with local variables inside linq2sql for F#?
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:
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.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.
精彩评论