Linq SqlDataProvider-动态编写where子句并执行命令
我有以下要求: 使用动态生成的where子句查询SQL表,该子句应在运行时由列表组成Linq SqlDataProvider-动态编写where子句并执行命令,linq,f#,Linq,F#,我有以下要求: 使用动态生成的where子句查询SQL表,该子句应在运行时由列表组成 [<Literal>] let connectionString = "Data Source=..." type sql = SqlDataProvider< ConnectionString = connectionString, DatabaseVendor = Common.DatabaseProviderTy
[<Literal>]
let connectionString = "Data Source=..."
type sql = SqlDataProvider<
ConnectionString = connectionString,
DatabaseVendor = Common.DatabaseProviderTypes.MSSQLSERVER,
UseOptionTypes = true>
let ctx = sql.GetDataContext()
type Key = {k:string;v:string}
let findCustomersByKeys (keys:Key list) =
query{
for c in ctx.Dbo.Customers do
where (keys.Any(fun k -> c.k = k.k && c.v = k.v))//this is what i wish i could do
select c
}
[]
让connectionString=“数据源=…”
类型sql=SqlDataProvider<
ConnectionString=ConnectionString,
DatabaseVendor=Common.DatabaseProviderTypes.MSSQLSERVER,
UseOptionTypes=true>
设ctx=sql.GetDataContext()
类型Key={k:string;v:string}
让我们查找客户密钥(密钥:密钥列表)=
质疑{
对于ctx.Dbo.Customers中的c
where(key.Any(fun k->c.k=k.k&&c.v=k.v))//这就是我希望能做的
选择c
}
有没有办法用SqlDataProvider在F#中实现这一点?
还有其他技术吗?您可以使用它动态构造谓词,并将其直接拼接到查询表达式中,因为查询表达式实际上是编译成引号的
谓词是通过折叠键、递归地将or条件拼接到初始条件false
上而构建的。但是,因为我们不能在这里结束c
,所以我们还需要将每个条件包装在一个函数中,并通过谓词链执行参数
open Microsoft.FSharp.Quotations
type Key = {k:string;v:string}
let findCustomersByKeys (keys:Key list) =
let predicate =
keys
|> List.fold
(fun (acc: Expr<Key -> bool>) k ->
<@ fun c -> (%acc) c || c.k = k.k && c.v = k.v @>)
<@ fun c -> false @>
query {
for c in ctx.Dbo.Customers do
where ((%predicate) c)
select c
}
打开Microsoft.FSharp.quotes
类型Key={k:string;v:string}
让我们查找客户密钥(密钥:密钥列表)=
let谓词=
钥匙
|>List.fold
(乐趣(acc:Expr bool>)k->
(%acc)c|c.k=k.k&&c.v=k.v@>)
假@>
质疑{
对于ctx.Dbo.Customers中的c
其中((%谓词)c)
选择c
}
您可以使用动态构造谓词,并将其直接拼接到查询表达式中,因为查询表达式实际上是编译成引号的
谓词是通过折叠键、递归地将or条件拼接到初始条件false
上而构建的。但是,因为我们不能在这里结束c
,所以我们还需要将每个条件包装在一个函数中,并通过谓词链执行参数
open Microsoft.FSharp.Quotations
type Key = {k:string;v:string}
let findCustomersByKeys (keys:Key list) =
let predicate =
keys
|> List.fold
(fun (acc: Expr<Key -> bool>) k ->
<@ fun c -> (%acc) c || c.k = k.k && c.v = k.v @>)
<@ fun c -> false @>
query {
for c in ctx.Dbo.Customers do
where ((%predicate) c)
select c
}
打开Microsoft.FSharp.quotes
类型Key={k:string;v:string}
让我们查找客户密钥(密钥:密钥列表)=
let谓词=
钥匙
|>List.fold
(乐趣(acc:Expr bool>)k->
(%acc)c|c.k=k.k&&c.v=k.v@>)
假@>
质疑{
对于ctx.Dbo.Customers中的c
其中((%谓词)c)
选择c
}
我的意思是,只有在运行时才能知道列表的大小,并且可以编译where子句。当您听到动态生成时,开始使用ORM,比如Dapper。另一种方法是按照答案中的建议,使用引号生成查询,但面对现实,每个人都会因此而恨你。我也做过一次:当然你也可以使用dynamic/expandoobject。我的意思是,只有在运行时才能知道列表的大小,并且可以编译where子句。当你听到动态生成时,开始使用ORM,比如Dapper。另一种方法是按照答案中的建议,使用引号生成查询,但面对现实,每个人都会因此而恨你。我也做过一次:当然你也可以使用dynamic/expandoobject。更新了答案。这比我想象的要复杂,有很多边缘案例,但我认为结果相当可读。更新了答案。这比我想象的要复杂,有很多边缘案例,但我认为结果相当可读。