F# linq2SQL bug or my fail?
I already sent the bug to fsbugs@microsoft.com but I also added this link to letter for additional description, code highlighting, discussions and maybe someone find some way to avoid it, because I really like it and want to use.
Code :
<@ seq {for a in db.ArchiveAnalogs do
for d in db.Deltas do
if a.ID = d.ID then
if a.Value > d.DeltaLimit then
yield a.Date, d.AboveMessage
else if a.Value < d.DeltaLimit then
yield a.Date, d.BelowMessage}
@> |> query |> Array.ofSeq
Same error messages with update :
<@ seq {for a in db.ArchiveAnalogs do
for d in db.Deltas do
if a.ID = d.ID && a.Value > d.DeltaLimit then
yield a.Date, d.AboveMessage
开发者_Python百科 elif a.ID = d.ID && a.Value < d.DeltaLimit then
yield a.Date, d.BelowMessage}
@> |> query |> Array.ofSeq
Error message :
The following construct was used in query but is not recognised by the
F#-to-LINQ query translator: Call (None, System.Collections.Generic.IEnumerable
1[System.Tuple
2[System.DateTime,System.String]] Singleton[Tuple2](System.Tuple
2[System.DateTime,System.String]), [NewTuple (PropertyGet (Some (a), System.DateTime Date, []), PropertyGet (Some (d), System.String AboveMessage, []))]) This is not a valid query expression. Check the specification of permitted queries and consider moving some of the query out of the quotation
Fixed
Code :
let px =
query <|
<@ seq { for cl in db.Dictionaries -> cl }
|> Seq.filter(fun x -> x.ID_Line = l1 || x.ID_Line = l2) @>
|> fun pquery ->
query <|
<@ seq { for cd in db.DeltaCompares do
for cl1 in pquery do
if cd.IID1 = cl1.IID then
for cl2 in pquery do
if cd.IID2 = cl2.IID then
yield cl1
yield cl2 } @>
|> List.ofSeq
Same error with update :
let p =
[for cl in db.Dictionaries -> cl]
|> Seq.filter(fun x -> x.ID_Line = l1 || x.ID_Line = l2)
|> fun pquery ->
<@ seq { for cd in db.DeltaCompares do
for cl1 in pquery do
for cl2 in pquery do
if cd.IID1 = cl1.IID && cd.IID2 = cl2.IID then
yield cl1, cl2 } @>
|> query |> Seq.collect(fun a -> [fst a; snd a])
Error message :
The following construct was used in query but is not recognised by the F#-to-LINQ query translator: Call (None, System.Collections.Generic.IEnumerable`1[LinqBase.Dictionary] SingletonDictionary, [cl1]) This is not a valid query expression. Check the specification of permitted queries and consider moving some of the query out of the quotation
fixed
I'm not sure if I do it correct so I also ask you to confirm if this is a bug or not a bug
In the first case, I think the F#-to-LINQ translator may be failing on nested if
. Have you tried: (...)
EDIT [Second attempt]: It could also fail because we're using if
without else
clause. What if you always return something using option
type and then filter out None
values (there may be a way to make it nicer, but let's start with this):
<@ seq {for a in db.ArchiveAnalogs do
for d in db.Deltas do
yield
if a.ID = d.ID && a.Value > d.DeltaLimit then
Some(a.Date, d.AboveMessage)
elif a.ID = d.ID a.Value < d.DeltaLimit then
Some(a.Date, d.BelowMessage)
else None }
@> |> query |> Seq.choose id |> Array.ofSeq
In the second case, it may be failing because of the for
nested in if
. I'd try this (...)
EDIT: This is actually incorrect use of LINQ (and it wouldn't work in C# too). The problem is that you're collecting some data in memory (pquery
) and then passing this as an input to the LINQ (so that it would have to send the data back to the SQL server.
You can try writing it like this (BTW: I think using |> fun x ->
is a weird construct when you can write the same thing simply just using let
):
let pquery = <@ db.Dictionaries
|> Seq.filter(fun x -> x.ID_Line = l1 || x.ID_Line = l2) @>
let px =
<@ seq { for cd in db.DeltaCompares do
for p in %pquery do ... } |> query
This is using quotation splicing. For more information about this feature, see my article (search for splicing).
精彩评论