gpt4 book ai didi

exception - F#异常处理多个 "Tries"

转载 作者:行者123 更新时间:2023-12-04 07:59:00 24 4
gpt4 key购买 nike

我正在尝试使用 SQL 批量插入和 DataContext.ExecuteCommand 在 SQL Server 中读取一堆 csv 文件。 (也许这不是最好的方法,但它确实允许我留在 Type Provider 上下文中,而不是我认为的 SqlBulkCopy。)现在上传出现故障,间歇性成功。一些文件读入,一些文件因“数据转换错误(截断)”而失败。我认为这与行终止符并不总是有效有关。

当上传成功时,它似乎带有'0x0A' 终止符。但是当失败时,我想用其他行终止符再次尝试。所以我想进入一个 Try 语句,如果失败则进入另一个 Try 语句,如果失败则进入另一个 Try 语句,...。这可能不是最好的上传方式,但我仍然对它自己状态的 Try 逻辑感到好奇。

这是我到目前为止的想法,它不是很漂亮(但它有效)。切出几个嵌套层:

let FileRead path = 

try
db.DataContext.ExecuteCommand(@"BULK INSERT...ROWTERMINATOR='0x0A')") |> ignore
true
with
| exn ->
try
db.DataContext.ExecuteCommand(@"BULK INSERT...ROWTERMINATOR='\r')") |> ignore
true
with
| exn ->
try
db.DataContext.ExecuteCommand(@"BULK INSERT...ROWTERMINATOR='\n')") |> ignore
true
with
| exn ->
false

这感觉不对,但我还没有想出任何其他语法。

编辑:我最终做了什么,仅供记录。感谢被放在富有成效的道路上。这方面有很多需要改进的地方。其中一件更重要的事情是使用 Async 并并行运行它(我在其他部分已经获得了经验)。

type dbSchema = SqlDataConnection<dbConnection>
let db = dbSchema.GetDataContext()

let TryUpLd table pathFile rowTerm =
try
db.DataContext.ExecuteCommand( @"BULK INSERT " + table + " FROM '" + pathFile +
@"' WITH (FIELDTERMINATOR=',', FIRSTROW = 2, ROWTERMINATOR='"
+ rowTerm + "')" ) |> ignore
File.Delete (pathFile) |> Some
with
| exn -> None

let NxtUpLd UL intOpt =
match intOpt with
| None -> UL
| _ -> intOpt

let MoveTable ID table1 table2 =
//...
()

let NxtMoveTable MT intOpt =
match intOpt with
| Some i -> MT
| _ -> ()

let UpLdFile path (file:string) =
let (table1, table2) =
match path with
| p when p = dlXPath -> ("Data.dbo.ImportXs", "Data.dbo.Xs")
| p when p = dlYPath -> ("Data.dbo.ImportYs", "Data.dbo.Ys")
| _ -> ("ERROR path to tables", "")

let ID = file.Replace(fileExt, "")

let TryRowTerm = TryUpLd table1 (path + file)

TryRowTerm "0x0A"
|> NxtUpLd (TryRowTerm "\r")
|> NxtUpLd (TryRowTerm "\n")
|> NxtUpLd (TryRowTerm "\r\n")
|> NxtUpLd (TryRowTerm "\n\r")
|> NxtUpLd (TryRowTerm "\0")
|> NxtMoveTable (MoveTable ID table1 table2)


let UpLdData path =
let dir = new DirectoryInfo(path)
let fileList = dir.GetFiles()

fileList |> Array.iter (fun file -> UpLdFile path file.Name ) |> ignore

最佳答案

这是一种方法,使用单子(monad)组合。

首先,定义一个函数,它将另一个函数作为输入,但将任何异常转换为 None 值:

let attempt f =
try f () |> Some
with | _ -> None

这个函数的类型是(unit -> 'a) -> 'a option;即:f 被推断为任何将 unit 作为输入并返回值的函数。如您所见,如果没有异常发生,调用 f 的返回值将包装在 Some 案例中。 attempt 函数会抑制所有异常,即 you shouldn't normally do .

接下来,定义这个 attemptNext 函数:

let attemptNext f = function
| Some x -> Some x
| None -> attempt f

此函数的类型为 (unit -> 'a) -> 'a option -> 'a option。如果输入的 'a optionSome 那么它就会被简单地返回。换句话说,该值被解释为已经成功,因此没有理由尝试下一个函数。

否则,如果输入的'a optionNone,这将被解释为好像上一步导致了失败。在这种情况下,将使用 attempt 函数尝试输入函数 f

这意味着您现在可以将函数组合在一起,并获得第一个成功的结果。

这里有一些函数可以用来测试:

let throwyFunction () = raise (new System.InvalidOperationException("Boo"))
let throwyFunction' x y = raise (new System.InvalidOperationException("Hiss"))
let goodFunction () = "Hooray"
let goodFunction' x y = "Yeah"

在 F# Interactive 中试用它们:

> let res1 =
attempt throwyFunction
|> attemptNext (fun () -> throwyFunction' 42 "foo")
|> attemptNext goodFunction
|> attemptNext (fun () -> goodFunction' true 13.37);;

val res1 : string option = Some "Hooray"

> let res2 =
attempt goodFunction
|> attemptNext throwyFunction
|> attemptNext (fun () -> throwyFunction' 42 "foo")
|> attemptNext (fun () -> goodFunction' true 13.37);;

val res2 : string option = Some "Hooray"

> let res3 =
attempt (fun () -> throwyFunction' 42 "foo")
|> attemptNext throwyFunction
|> attemptNext (fun () -> goodFunction' true 13.37)
|> attemptNext goodFunction;;

val res3 : string option = Some "Yeah"

> let res4 =
attempt (fun () -> throwyFunction' 42 "foo")
|> attemptNext (fun () -> goodFunction' true 13.37)
|> attemptNext throwyFunction
|> attemptNext goodFunction;;

val res4 : string option = Some "Yeah"

关于exception - F#异常处理多个 "Tries",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32662563/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com