开发者

F# linq2SQL bug or my fail?

开发者 https://www.devze.com 2023-02-12 21:54 出处:网络
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 re

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.IEnumerable1[System.Tuple2[System.DateTime,System.String]] Singleton[Tuple2](System.Tuple2[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).

0

精彩评论

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