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

3

我正在尝试查询解析后的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没有null作为适当的值”。这有点说得通,但我仍然想捕获文件中不存在id的情况。我猜我可以将headOrDefault更改为head并捕捉异常,但我想知道是否有更好的方法。
更新#1: 根据评论中的链接之一,我能够摆脱
    if obj.ReferenceEquals(res,null)
        then NOT_FOUND("")
        else OK(res.JsonValue.ToString())
    )

更新 #2: 虽然上述代码可行,但语言仍感不自然。接受的答案看起来更加自然。

请查看此答案:https://dev59.com/f2gt5IYBdhLWcg3w8h41#11696947,虽然它是一个更一般性的问题,但解决方案应该适用。 - scrwtp
可能是Type does not have null as a proper value的重复问题。 - scrwtp
@scrwtp 这不是 https://dev59.com/f2gt5IYBdhLWcg3w8h41 的重复,除非有一种方法可以将 AllowNullLiteral 属性应用于 OrdersProvider.Root。然而,另一个链接帮了我大忙。我成功地使用了 obj.ReferenceEquals。 - AlexanderM
这就是为什么我链接到那个答案的原因 ;) - scrwtp
1个回答

2
我认为headOrDefault操作是为了与LINQ to SQL兼容而设计的,这就是为什么它在默认情况下返回null - 这不是您通常希望在良好行为的F#代码中使用的内容,因此按照您的查询方式使用它并不是一个好主意。
幸运的是,headOrDefault将与F#选项类型一起使用 - 如果您从select子句中返回Some,则headOrDefault在值不可用时返回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())

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接