如何在 F# 中使用 Sqlprovider 映射可为空的 Guid 字段

How to Map Nullable Guid Field with Sqlprovider in F#

我遇到错误:

System.InvalidCastException: 'Unable to cast object of type 'System.Guid'
to type 'Microsoft.FSharp.Core.FSharpOption`1

使用此代码:

let products = 
    query {
        for product in ctx.Dbo.Products do
            select product
    } 
    |> Seq.map(fun p -> p.MapTo<Product>())
    |> Seq.toList

我已将我的类型缩小到几个字段以查看发生了什么

type Product = {
    Id: Guid
    SellDiscountCalcTypeId: Option<Guid>
    Code: string
}

并且我的数据提供者设置正确(useOptionTypes = true)

type smBoomProvider =
    SqlDataProvider<
        DatabaseVendor = Common.DatabaseProviderTypes.MSSQLSERVER,
        ConnectionString = smBoomConn,
        IndividualsAmount = 1000,
        UseOptionTypes = true
    >

对于全为空的字段,没有错误,但一旦字段中有任何内容,它就会在运行时出错。

不幸的是,MapTo 方法似乎不支持 UseOptionTypes 标志。你可以解决这个问题,但它并不漂亮。一种方法是手动映射列:

let mapping (col : string, value : obj) =
    match col with
        | "SellDiscountCalcTypeId" ->
            if isNull value then None
            else Some (value :?> Guid)
            :> obj
        | _ -> value

let products = 
    query {
        for product in ctx.Dbo.Products do
            select product
    } 
    |> Seq.map (fun p -> p.MapTo<Product>(mapping))   // use manual mapping
    |> Seq.toList

另一个是显式 select 各个字段。这将尊重 UseOptionTypes 标志,至少:

module Product =

    let create (id, sellDiscountCalcTypeId, code) =
        {
            Id = id
            SellDiscountCalcTypeId = sellDiscountCalcTypeId
            Code = code
        }

let products = 
    query {
        for product in ctx.Dbo.Products do
            select (product.Id, product.SellDiscountCalcTypeId, product.Code)   // explicitly select fields
    } 
    |> Seq.map Product.create
    |> Seq.toList