F#异常处理多个“ Tries” [英] F# exception handling multiple "Tries"

查看:82
本文介绍了F#异常处理多个“ Tries”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用SQL Bulk Insert和DataContext.ExecuteCommand在SQL Server中读取一堆csv文件。 (也许这不是最好的方法,但它确实允许我停留在Type Provider上下文中-与我认为的SqlBulkCopy相对。)现在,上传失败并间歇性地成功。某些文件已读入,有些则失败并显示数据转换错误(截断)。我认为这与行终止符不总是有效有关。

I'm trying to read a bunch of csv files in SQL Server using SQL Bulk Insert and DataContext.ExecuteCommand. (Maybe this isn't the best way to do it, but it does allow me stay in the Type Provider context--as opposed to with SqlBulkCopy I think.) Now the upload is glitchy with intermittent success. Some files read in, some fail with "Data conversion error (truncation)". I think this has to do with the row terminators not always working.

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

When the upload works, it seems to be with the '0x0A' terminator. But when that fails, I want to try repeatedly again with other row terminators. So I want to go into a Try statement, and on failure go into another Try statement, and another if that one fails, ... . This may not be the best way to upload, but I am still curious about the Try logic for it's own state.

到目前为止,这是我要提出的内容,虽然不是很漂亮(但可以)。删除一些嵌套层:

Here's what I've come up with so far and it's not too pretty (but it works). Cutting out a few nested layers:

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

这感觉不对,但我还没有弄清楚其他语法。

This doens't feel right but I haven't figured out any other syntax.

编辑:我最终所做的只是为了记录。赞赏被置于生产性道路上。有很多可以改进的地方。更重要的事情之一就是使用Async并使其并行运行(我在其他部分已经获得了经验)。

What I ended up doing, just for the record. Appreciate being put on a productive path. There's plenty to improve in this. With one of the more significant things being to use Async's and run it Parallel (which I have gotten experience with in other sections).

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


推荐答案

这是使用单调组合的一种方法

Here's one way to do it, using monadic composition.

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

First, define a function that takes another function as input, but converts any exception to a None value:

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

此函数的类型为(unit->'a)- >一个选项;即: f 推断为以 unit 作为输入并返回值的任何函数。如您所见,如果没有异常发生,则调用 f 的返回值将包装在 Some 情况下。 尝试函数可抑制所有您通常不应该这样做

This function has the type (unit -> 'a) -> 'a option; that is: f is inferred to be any function that takes unit as input, and returns a value. As you can see, if no exception happens, the return value from invoking f is wrapped in a Some case. The attempt function suppresses all exceptions, which you shouldn't normally do.

下一步,定义此 attemptNext 函数:

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

此函数的类型为(unit->'a) ->一个选项->一个选项。如果输入的’选项一些,则只需返回。换句话说,该值被解释为已经成功,因此没有理由尝试下一个函数。

This function has the type (unit -> 'a) -> 'a option -> 'a option. If the input 'a option is Some then it's simply returned. In other words, the value is interpreted as already successful, so there's no reason to try the next function.

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

Otherwise, if the input 'a option is None, this is interpreted as though the previous step resulted in a failure. In that case, the input function f is attempted, using the attempt function.

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

This means that you can now compose functions together, and get the first successful result.

以下是一些可以测试的函数:

Here are some functions to test with:

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中尝试一下:

Try them out in 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"

这篇关于F#异常处理多个“ Tries”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆