f#查询表达式按列表{Id}获取元素

时间:2018-06-07 12:37:12

标签: f#

我正在使用f#来更新csv文件中的数据库,所以我使用Fsharp.Data来解析它,它按预期运行良好,然后SqlProvider来实现更新。
所以我从我的csv获得list个项目,其中一个字段是我要更新的表的标识符。我来自c#背景,所以使用LINQ我可以这样做:

var results = context.MyTable.Where(m => myList.Contains(m.Identifier))

这会给我我正在寻找的行。我试着这样做

query {
    for m in ctx.Dbo.MyTable do
    where (List.contains m.Identifier myList)
    select m
}

并在运行时遇到此错误:

  

System.InvalidOperationException:从范围''引用的'FSharp.Data.Sql.Common.SqlEntity'类型的变量'm',但未定义
     在Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.EvaluateQuotation(FSharpExpr e)
     在Microsoft.FSharp.Linq.QueryModule.EvalNonNestedInner(CanEliminate canElim,FSharpExpr queryProducingSequence)
     在Microsoft.FSharp.Linq.QueryModule.clo@1727-1.Microsoft-FSharp-Linq-ForwardDeclarations-IQueryMethods-Execute [a,b](FSharpExpr`1 q)
     at。$ FSI_0006.main @()
  因错误而停止

然后尝试了以下

query {
    for m in ctx.Dbo.MyTable do
    for id in myList do
    where (id = m.Identifier)
    select m
}

并在编译时得到了这个:

  

myScript.fsx(291,30):错误FS0001:“字符串列表”类型与“System.Linq.IQueryable”类型不兼容

我确信这可以做到,我想知道我做错了什么

正确的方法是什么?
我认为这显然是错的是什么?

更新

我刚跟着Aaron回答,这就是我的代码现在的样子,至少是相关部分:

let ctx = Sql.GetDataContext();

let getZipCodes (zipcodes: string list) = 
    query {
        for zc in ctx.CleanZipCodes do
        for id in zipcodes do
        where (id = zc.ZipCode)
        select zc
    }
    |> Seq.toList

现在我收到了这个错误:

  

System.Data.EntityCommandExecutionException:执行命令定义时发生错误。有关详细信息,请参阅内部异常--->

     

System.Data.SqlClient.SqlException:SQL语句的某些部分嵌套太深。重写查询或将其分解为较小的查询。      在System.Data.SqlClient.SqlConnection.OnError(SqlException异常,Boolean breakConnection,Action'1 wrapCloseInAction)
     在System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj,Boolean callerHasConnectionLock,Boolean asyncClose)
     在System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior,SqlCommand cmdHandler,SqlDataReader dataStream,BulkCopySimpleResultSet bulkCopyHandler,TdsParserStateObject stateObj,Boolean& dataReady)
     在System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
     在System.Data.SqlClient.SqlDataReader.get_MetaData()
     在System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds,RunBehavior runBehavior,String resetOptionsString,Boolean isInternal,Boolean forDescribeParameterEncryption,Boolean shouldCacheForAlwaysEncrypted)
     在System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(的CommandBehavior cmdBehavior,RunBehavior runBehavior,布尔returnStream,布尔异步,的Int32超时,任务&安培;任务,布尔asyncWrite,布尔inRetry,SqlDataReader的DS,布尔describeParameterEncryptionRequest)
     在System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior,RunBehavior runBehavior,Boolean returnStream,String method,TaskCompletionSource'1 completion,Int32 timeout,Task& task,Boolean& usedCache,Boolean asyncWrite,Boolean inRetry)
     在System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior,RunBehavior runBehavior,Boolean returnStream,String method)
     在System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior,String method)
     在System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand,CommandBehavior behavior)

     

---内部异常堆栈跟踪结束---

     

at System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand,CommandBehavior behavior)
     at System.Data.Objects.Internal.ObjectQueryExecutionPlan.Execute [TResultType](ObjectContext context,ObjectParameterCollection parameterValues)
     在System.Data.Objects.ObjectQuery'1.GetResults(Nullable'1 forMergeOption)      at System.Data.Objects.ObjectQuery'1.System.Collections.Generic.IEnumerable.GetEnumerator()
     在Microsoft.FSharp.Collections.SeqModule.ToList [T](IEnumerable'1 source)
     at。$ FSI_0006.main @()

1 个答案:

答案 0 :(得分:3)

第二个示例中的错误似乎是LINQ to SQL的问题。您可以使用SQL实体类型提供程序解决它,该提供程序在内置类型提供程序中称为SqlEntityConnection

#r "System.Data.Entity"
#r "FSharp.Data.TypeProviders"

open Microsoft.FSharp.Data.TypeProviders

type SqlDb = SqlEntityConnection<"...">

let context = SqlDb.GetDataContext()

let myList = [...]

query {
    for record in context.MyTable do
    for id in myList do
    where (id = record.Identifier)
    select record
} |> Seq.toList