我正在用F#重写一个C#库,其中大多数类与数据库表一对一映射(类似于ActiveRecord)。我正在考虑是否使用记录或类(甚至可能是DU?)。在属性设置器中有相当多的验证来维护不变量。 在F#中对此进行建模的最佳方法是什么?我不希望将违反业务逻辑的对象持久保存到数据库中。欢迎任何想法。
一些额外的想法...... 将不变量移动到外部“控制器”类是否更好?来自C#,允许与数据库记录对应的对象包含无法保存到数据库的任何内容,这是错误的。我想,因为早先失败似乎比以后失败更好。
答案 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/