F# SqlProvider递归组合查询

F# SqlProvider递归组合查询,f#,fsharp.data.typeproviders,F#,Fsharp.data.typeproviders,使用SqlProvider类型提供程序,我试图做一些事情,递归地折叠“查询标准”列表 type Criterion = { Column : string Operator : string Value : string } 这样表达式树只被编译到SQL一次,而我不会多次访问数据库。我尝试过几种方法,其中最成功的是这样的 let rec eval (acc : IQueryable<SourceEntity> option) (qrys : Criterio

使用SqlProvider类型提供程序,我试图做一些事情,递归地折叠“查询标准”列表

type Criterion = {
    Column : string
    Operator : string
    Value : string
}
这样表达式树只被编译到SQL一次,而我不会多次访问数据库。我尝试过几种方法,其中最成功的是这样的

let rec eval (acc : IQueryable<SourceEntity> option) (qrys : Criterion list) =
match qrys with
|[] -> acc
|x :: xs -> let acc' = let op,valu = translateOpnValu x
                       match acc with
                       |Some acc' -> query {
                                            for elem in acc' do
                                            where (elem.GetColumn x.Column op valu)
                                            select elem 
                                     } |> Some
                       |None     -> query {
                                            for elem in ctx.Dbo.Source do
                                            where (elem.GetColumn x.Column op valu)
                                            select elem 
                                     } |> Some
            eval acc' xs
我得到了这个豁免

System.Exception: Unsupported expression. Ensure all server-side objects appear on the left hand side of predicates.  The In and Not In operators only support the inline array syntax. InvokeFast(elem.GetColumn("Source Code"), value(FSI_0006+acc'@38-2), "%BEN%")
at Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.EvaluateQuotation(FSharpExpr e)
at Microsoft.FSharp.Linq.QueryModule.EvalNonNestedInner(CanEliminate canElim, FSharpExpr queryProducingSequence)
at Microsoft.FSharp.Linq.QueryModule.EvalNonNestedOuter(CanEliminate canElim, FSharpExpr tm)
at Microsoft.FSharp.Linq.QueryModule.clo@1735-1.Microsoft-FSharp-Linq-ForwardDeclarations-IQueryMethods-Execute[a,b](FSharpExpr`1 )
at FSI_0006.evaluate(FSharpOption`1 acc, FSharpList`1 qrys) in F:\code_root\vs2015\F\CAMS\CAMS\scratch.fsx:line 47
at <StartupCode$FSI_0007>.$FSI_0007.main@() in F:\code_root\vs2015\F\CAMS\CAMS\scratch.fsx:line 60
如果我用一个隐式运算符=/=%替换TranslateOnValu返回的“op”,它可以正常工作


我有一种感觉,这与返回的运算符类型被约束为string->string->bool有关,而隐式运算符更通用。如何让translateOnValu函数返回更多的泛型运算符?或者,这根本不是问题所在……

@Fyodor是正确的-为了让SQL提供程序正确地提取您的函数,您需要将其包装在引号中,并将其拼接到查询表达式中。像这样的方法应该会奏效:

let translateOpnValu (c:Criterion) =
     match c.Operator with
     |"%=%" -> <@ (=%) @>, sprintf "%%%s%%" c.Value
     |_     -> <@ (=) @>, c.Value

// ...

query {
    for elem in acc' do
    where ((%op) (elem.GetColumn x.Column) valu)
    select elem 
}

由于op未命名为运算符,因此不能在中缀符号中应用。请改为尝试前缀:op elem.GetColumn x.Column values谢谢,这是一个很好的建议,但是,唉,我仍然得到相同的异常……然后我假设SqlProvider的引号解析器只需要运算符本身,而不需要任何别名。尝试从TranslateOnValu返回一个引用并将其拼接到中。
let translateOpnValu (c:Criterion) =
     match c.Operator with
     |"%=%" -> <@ (=%) @>, sprintf "%%%s%%" c.Value
     |_     -> <@ (=) @>, c.Value

// ...

query {
    for elem in acc' do
    where ((%op) (elem.GetColumn x.Column) valu)
    select elem 
}