JsonProvider<...>.Root 没有 null 作为正确的值

JsonProvider<...>.Root does not have null as proper value

我正在尝试查询已解析的结果 Json,如果找不到,我想做其他事情。

[
  {
    "orderId": 136,
    "quantity": 5,
    "price": 3.75
  },
  {
    "orderId": 129,
    "quantity": 9,
    "price": 3.55
  },
  {
    "orderId": 113,
    "quantity": 11,
    "price": 3.75
  }
]

我的代码是这样的:

type OrdersProvider = JsonProvider<"Orders.json">
let orders = OrdersProvider.GetSamples()

let test id =
    let res = query{
                    for i in orders do
                        where (i.OrderId = id)
                        select i
                        headOrDefault
                }

    if isNull(res)
        then NOT_FOUND("")
        else OK(res.JsonValue.ToString())
    )

但是我收到编译器错误 "JsonProvider<...>.Root does not have null as proper value"。这是有道理的,除非我仍然想抓住 id 不在文件中的情况。我想我可以将 headOrDefault 更改为 head 并捕获异常,但想知道是否有更好的方法。

更新#1: 通过评论中的一个链接,我得以逃脱

    if obj.ReferenceEquals(res,null)
        then NOT_FOUND("")
        else OK(res.JsonValue.ToString())
    )

更新#2: 虽然提到的代码有效,但对于该语言来说仍然感觉不自然。接受的答案看起来更自然。

我认为 headOrDefault 操作是为了与 LINQ to SQL 兼容而设计的,这就是为什么它在默认情况下 returns null - 这不是您通常希望在表现良好的 F# 代码中使用它,因此以您的查询方式使用它并不是一个好主意。

幸运的是,headOrDefault 将与 F# 选项类型一起使用 - 如果您从 select 子句中 return Some 然后 headOrDefault return s None 当值不可用时:

let res = 
  query {
    for i in orders do
    where (i.OrderId = id)
    select (Some i)
    headOrDefault }

现在您可以使用模式匹配处理丢失的情况:

match res with
| None -> NOT_FOUND("")
| Some order -> OK(order.JsonValue.ToString())