将数据库记录建模为类型

时间:2010-01-18 22:34:16

标签: f#

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

一些额外的想法...... 将不变量移动到外部“控制器”类是否更好?来自C#,允许与数据库记录对应的对象包含无法保存到数据库的任何内容,这是错误的。我想,因为早先失败似乎比以后失败更好。

3 个答案:

答案 0 :(得分:3)

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

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())

记录的复制语义几乎与设置属性一样方便。验证不会在属性集上发生,但很容易将记录列表过滤到仅有效的记录。

答案 1 :(得分:2)

这实际上应该是你处理它的好方法。在构造函数中使用验证逻辑将在稍后的代码中让您放心,因为该对象是不可变的。这也开启了多线程的可能性。

不可变版本

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)    

可变版本

type Customer (id) =

    let mutable name = ""

    do // Constructor
        if id <= 0 then 
            raise(new ArgumentException("Invalid ID.", "id"))

    member this.ID
        with get() = id
    member this.Name
        with get() = name  
        and set value =
            if String.IsNullOrEmpty(name) then 
                raise(new ArgumentException("Invalid Name.", "value")) 
            name <- value

答案 2 :(得分:0)

你看过我的FunctionalNHibernate项目了吗?它被设计为nhibernate之上的一个层,允许您以声明方式将记录映射到数据库。这是早期的,但它只是可用: http://bitbucket.org/robertpi/functionalnhibernate/