F# 将数据库记录建模为类型

F# 将数据库记录建模为类型,f#,F#,我正在用F#重写一个C#库,其中大多数类与数据库表一一映射(类似于ActiveRecord)。我正在考虑是否使用记录或类(甚至可能是DU?)。在属性设置器中有大量的验证来维护不变量。用F#来模拟这一点的最佳方法是什么?我不想将违反业务逻辑的对象持久化到数据库中。欢迎提出任何意见 还有一些想法。。。 将不变量移动到外部“控制器”类是否更好?从C#开始,允许与数据库记录相对应的对象包含任何无法保存到数据库的内容感觉是错误的。我想是因为早失败似乎比晚失败好。这实际上应该是你处理问题的好方法。将验证逻辑

我正在用F#重写一个C#库,其中大多数类与数据库表一一映射(类似于ActiveRecord)。我正在考虑是否使用记录或类(甚至可能是DU?)。在属性设置器中有大量的验证来维护不变量。用F#来模拟这一点的最佳方法是什么?我不想将违反业务逻辑的对象持久化到数据库中。欢迎提出任何意见

还有一些想法。。。
将不变量移动到外部“控制器”类是否更好?从C#开始,允许与数据库记录相对应的对象包含任何无法保存到数据库的内容感觉是错误的。我想是因为早失败似乎比晚失败好。

这实际上应该是你处理问题的好方法。将验证逻辑放在构造函数中会让您在以后的代码中有更多的想法,因为对象是不可变的。这也打开了多线程的可能性

不可变版本

type Customer (id, name) =

    do // Constructor
        if id <= 0 then 
            raise(new ArgumentException("Invalid ID.", "id"))
        elif String.IsNullOrEmpty(name) then 
            raise(new ArgumentException("Invalid Name.", "name"))    

    member this.ID
        with get() = id
    member this.Name
        with get() = name

    member this.ModifyName value =
        new Customer(id, value)    
键入客户(id、名称)=
do//Constructor

如果id您可以将数据保存在记录中,并通过将方法附加到记录中来保持数据类型的验证逻辑:

type Person =
    { First : string;
      Last  : string; } with
    member x.IsValid () =
        let hasValue = System.String.IsNullOrEmpty >> not    
        hasValue x.First && hasValue x.Last

let jeff = { First = "Jeff"; Last = "Goldblum" }
let jerry = { jeff with First = "Jerry" }
let broken = { jerry with Last = "" }

let valid = [jeff; jerry; broken] 
            |> List.filter (fun x -> x.IsValid())

记录的复制语义几乎与设置属性一样方便。验证不会在属性集上进行,但可以很容易地将记录列表筛选为仅有效的记录。

您看过我的FunctionalHibernate项目了吗?它被设计为nhibernate之上的一个层,允许您以声明方式将记录映射到数据库。现在还为时尚早,但它几乎是可用的:

这些类型的大多数操作的形式为:加载、修改、保存。缺少类的复制语义(如记录),这似乎要求类型是可变的,并且在属性设置器中具有验证逻辑。因此基本上复制我在C#中的内容?是的,你并不真的想将验证与对象分开。我认为可能有一种方法可以提供函数式编程的一些额外好处。例如,记录具有不变性,易于复制和构造……但我无法控制它们的内容!关于函数式编程,我的第一个示例将是最有用的。唯一的限制是,如果要更改对象,则需要创建新实例。这实际上是一个您希望对象如何与代码的其余部分交互的问题。有人能建议一种更“功能性”(或完全不同)的方法吗?我确实有。我加入了谷歌集团,一直在关注进展。但是,由于我没有任何使用NHibernate的经验,而且我已经有了一个用C#编写的ORM(我正在转换),我一直不愿意大规模地切换到另一个ORM。另外,我想知道,自从NHibernate是为C#编写的,F#版本会利用函数式编程的任何好处吗?我希望看到一个从功能角度出发设计的ORM…希望它能尽可能地消除RDBMS/功能编程阻抗的不匹配。从功能角度出发重写是理想的,但从我的角度来看,NHibernate已经为抽象RDBMS提供了一些很好的特性,我认为从头重写这些特性非常耗时。或者换句话说,我不认为你能使用NH的所有内容,但你能在那里使用足够多的内容,让它变得值得。这种方法在F#中感觉非常自然,但我很难摆脱完全封装类的干净性。也许没有一个两全其美的解决方案。我只是在探索这些选项。你真的应该坚持使用漂亮的封装对象。
type Person =
    { First : string;
      Last  : string; } with
    member x.IsValid () =
        let hasValue = System.String.IsNullOrEmpty >> not    
        hasValue x.First && hasValue x.Last

let jeff = { First = "Jeff"; Last = "Goldblum" }
let jerry = { jeff with First = "Jerry" }
let broken = { jerry with Last = "" }

let valid = [jeff; jerry; broken] 
            |> List.filter (fun x -> x.IsValid())