F# 如何将数据库记录读入受歧视的联合?
假设我在F#中有以下内容: 其次是受歧视的工会:F# 如何将数据库记录读入受歧视的联合?,f#,discriminated-union,F#,Discriminated Union,假设我在F#中有以下内容: 其次是受歧视的工会: type Visit = | Scheduled of name: PersonName * appointmentTime: DateTime | WalkIn of name: PersonName * appointmentTime: DateTime * timeOfService: DateTime | KeptAppointment of name: PersonName * appointmentTime: DateTime *
type Visit =
| Scheduled of name: PersonName * appointmentTime: DateTime
| WalkIn of name: PersonName * appointmentTime: DateTime * timeOfService: DateTime
| KeptAppointment of name: PersonName * appointmentTime: DateTime * postingTime: DateTime * serviceTime: DateTime
| OpenSlot of appointmentTime: DateTime
with
member x.Name =
match x with
| Scheduled(name, _)
| WalkIn(name, _, _)
| KeptAppointment(name, _, _, _) -> Some name
| OpenSlot _ -> None
如果访问定义为简单记录,如:
type Visit = {
lastName : string
firstName : string
birthDate : DateTime
appointmentTime : Nullable<DateTime>
tservice : Nullable<DateTime>
postingTime : Nullable<DateTime>
chartNumber : Nullable<int>
}
但是,如果使用了Visit的第一个版本(歧视联盟),则“编译器”无法识别如何处理人名的生日、名和姓。显然,我没有正确地传达我的意图
那么,如何将数据库记录读入受歧视的联合?有许多不同的方法可以做到这一点;所有这些都与大多数ORM处理继承类的方式非常相似。然而,考虑到目前数据库的状况,还有其他方法 从根本上说,所有的联合都是由给定的“标记”分派的一组类型。对于每个标记/联合案例,都有一组必须定义的字段(记录)。因此,您需要在映射lambda中找到一种方法来检查某种条件,并适当地创建正确的联合类型
let GetScheduleAsync (tableDate : DateTime) =
async {
let! data = context.GetOfficeScheduleAsync(tableDate) |> Async.AwaitTask
return data |> Seq.map(fun q ->
match q.Tag with
| x when x = "Scheduled" -> Scheduled({ firstName = q.firstName; lastName = q.lastName; birthDate = q.BirthDate }, q.appointmentTime)
| _ -> failwithf "Insert other cases here"
)
}
|> Async.StartAsTask
如何确定“标记”实际上是数据库设计的一个问题,有许多不同的策略(例如,带有标记字段的单个表、每个具体类/标记的表)。一些数据库还允许JSON序列化(例如Postgres),如果您只想将union直接序列化/反序列化到字段中,可以选择JSON序列化。如何在数据库中表示数据以及如何将数据读入union构造函数完全取决于您。为此,我将为数据库IO创建一个层。DU数据的实体记录,只有基本类型,在需要时可为空,DU案例有一个字段。@BentTranberg请解释“DU案例有一个字段”是如何工作的?谢谢。是否可以直接使用上面“member x.Name”定义的模式匹配,而不添加与“when”相关的专门测试?谢谢。“让(|等于| | |)xy=如果x=y,那么其他一些就没有了”。然后你可以在任何你想要的地方使用它来进行对等匹配。“将x.名称与|等于(“x”)->…”匹配”。我不记得这是否有内在的匹配;常量模式可能会起作用,但如果我记得的话,它对字符串不起作用。因为如果您定义了枚举,那么您事先就知道这些情况,所以最好先尝试解析它,然后匹配枚举。这样,您就可以更改它在数据库(x.Name)中的表示方式,而无需稍后更改上述逻辑。通常,标记是类似Int的东西,而不是字符串,可以用这种方式在数据库中表示。
/// Get the office schedule for the tableDate.
let GetScheduleAsync (tableDate : DateTime) =
async {
let! data = context.GetOfficeScheduleAsync(tableDate) |> Async.AwaitTask
return data |> Seq.map(fun q -> {
Visit.lastName = q.lastname
firstName = q.firstname
birthDate = q.birthdate
appointmentTime = q.appointment_time
tservice = q.service_time
postingTime = q.posting_time
chartNumber = q.chart_number
})
}
|> Async.StartAsTask
let GetScheduleAsync (tableDate : DateTime) =
async {
let! data = context.GetOfficeScheduleAsync(tableDate) |> Async.AwaitTask
return data |> Seq.map(fun q ->
match q.Tag with
| x when x = "Scheduled" -> Scheduled({ firstName = q.firstName; lastName = q.lastName; birthDate = q.BirthDate }, q.appointmentTime)
| _ -> failwithf "Insert other cases here"
)
}
|> Async.StartAsTask