F# 中数据库记录的记录模式和类型不匹配

Mismatch in record pattern and type on database record in F#

如何修复以下错误?

此表达式的类型应为 'string * Nullable * Nullable' 但此处的类型为 'VisitType'(错误发生在"|AppointmentOnly(q.lastname, q.posting_time)).

字段'appointmentTime'不是静态的(错误发生在FsVisit.appointmentTime = q.appointment_time; ).

(这些错误发生在我尝试通过 WCF 从 PostgreSQL 数据库下载记录到 F# 客户端时)。

type VisitType = 
| AppointmentOnly of name: string * postedTime: DateTime
| WalkIn of name: string * serviceTime: DateTime
| Kept of name: string * postedTime: DateTime * serviceTime: DateTime
| Open


type FsVisit =
     { appointmentTime: Nullable<DateTime>
       visitType: VisitType }
with
    member this.Name =
       match this.visitType with
       | AppointmentOnly(name=name) | WalkIn(name=name) | Kept(name=name) -> Some name
       | Open -> None

let TestGetScheduleAsync (tableDate : DateTime) =
    async {
        let! data = context.GetOfficeScheduleAsync(tableDate) |> Async.AwaitTask
        return data |> Seq.map ( fun q -> 
            FsVisit.appointmentTime = q.appointment_time;
                      match (q.lastname, q.posting_time, q.service_time) with
                      | AppointmentOnly(q.lastname, q.posting_time) -> AppointmentOnly({name = q.lastname; postedTime = q.posting_time})
                      | WalkIn(q.lastname, q.service_time) -> WalkIn({name =q.lastname; serviceTime = q.service_time})
                      | Kept(q.lastname, q.posting_time, q.service_time) -> Kept({name=q.lastname; postedTime = q.posting_time, serviceTime = q.service_time})
                      | Open -> None

        )}
         |> Async.StartAsTask

感谢您的帮助。

lastnameposting_timeservice_time 的元组不是 VisitType 类型的值。所以你不能将它与 VisitType discriminated union cases 相匹配。我假设 posting_timeservice_timeNullable<DateTime> 值(与 appointment_time 相同)所以你应该将元组与元组匹配并根据 [=15 创建 VisitType 大小写=] 和 service_time 值(SomeNone)。我也会从匹配中删除名称

match (Option.ofNullable q.posting_time, Option.ofNullable q.service_time) with
| (Some postedTime, None) -> AppointmentOnly(q.lastname, postedTime)
| (None, Some serviceTime) -> WalkIn(q.lastname, serviceTime)
| (Some postedTime, Some serviceTime) -> Kept(q.lastname, postedTime, serviceTime)
| _ -> Open

如果您想要 VisitType option,您可以通过为 Open 案例返回 None 和为其他案例返回 Some 来调整此代码。


请注意,如果您添加 active patterns,您的代码也可以编译,这将为您的输入数据(元组)创建所谓的命名分区:

let (|AppointmentOnly|WalkIn|Kept|Open|)
    (name: string, postedTime: Nullable<DateTime>, serviceTime: Nullable<DateTime>) =
        match (Option.ofNullable postedTime, Option.ofNullable serviceTime) with
        | (Some postedTime, None) -> AppointmentOnly(name, postedTime)
        | (None, Some serviceTime) -> WalkIn(name, serviceTime)
        | (Some postedTime, Some serviceTime) -> Kept(name, postedTime, serviceTime)
        | (None, None) -> Open

请记住,此处返回的 AppointementOnlyWalkInKeptOpen 不是受歧视的联合案例 - 它是活动模式记录。现在您可以使用此活动模式将输入数据划分为分区并创建相应的 VisitType 个案例:

match (q.lastname, q.posting_time, q.service_time) with
| AppointmentOnly(name, postedTime) -> AppointmentOnly(name, postedTime)
| WalkIn(name, serviceTime) -> WalkIn(name, serviceTime)
| Kept(name, postedTime, serviceTime) -> Kept(name, postedTime, serviceTime)
| Open -> Open

同样,这里我们在活动模式上进行匹配,然后创建一个可区分的联合:

| AppointmentOnly(name, postedTime) -> AppointmentOnly(name, postedTime)
              ^                                    ^
     ACTIVE PATTERN IDENTIFIER                  UNION CASE