.net - F# 中的存储库模式

标签 .net f#

我正在开发一个使用文档数据库的原型(prototype)(目前是 MongoDB,可能会更改),并且发现 .NET 驱动程序有点麻烦,所以我想我应该使用存储库模式抽象数据访问。这应该可以轻松地将我现在使用的任何驱动程序(NoRM、mongodb-csharp、simple-mongob)替换为你的 killer 级 f# mongodb 驱动程序,当它准备好时,它不会太糟糕。 p>

我的问题是关于“添加”操作的。这将对数据库产生一些副作用,因此对 All 的后续调用将会有所不同。我应该关心吗?传统上在 C# 中我不会,但我觉得在 F# 中我应该这样做。

这是通用存储库接口(interface):

type IRepository<'a> =
    interface
        abstract member All : unit -> seq<'a>

        // Add has a side-effect of modifying the database
        abstract member Add : 'a -> unit
    end

这是 MongoDB 实现的样子:

type Repository<'b when 'b : not struct>(server:MongoDB.IMongo,database) =
    interface IRepository<'b> with

        member x.All() =
            // connect and return all

        member x.Add(document:'b) =
            // add and return unit

在整个应用程序中,我将使用 IRepository,从而可以轻松更改驱动程序和潜在的数据库。

调用 All 很好,但是使用 Add 我希望返回一个新的存储库实例,而不是返回单元。像这样的东西:

        // Add has a side-effect of modifying the database
        // but who cares as we now return a new repository
        abstract member Add : 'a -> IRepository<'a>

问题是,如果我调用 Get,然后调用 Add,原始存储库仍然返回所有文档。示例:

let repo1 = new Repository<Question>(server,"killerapp") :> IRepository<Question>
let a1 = repo1.All() 
let repo2 = repo1.Add(new Question("Repository pattern in F#"))
let a2 = repo2.All()

理想情况下,我希望 a1 和 a2 的长度不同,但它们是相同的,因为它们都访问数据库。该应用程序可以运行,用户可以提出他们的问题,但程序员想知道为什么它返回一个新的 IRepository。

那么我应该在类型设计中尝试处理 Add 对数据库的副作用吗?其他人会如何解决这个问题,您是否使用存储库或类似的接口(interface)类或有更好的功能方法?

最佳答案

看起来您正在将不变性应用于影响外部世界状态的函数。无论 F# 实现如何,您认为它在 MongoDB 级别如何工作?如何防止 repo1 看到 repo2 所做的任何更改?如果其他进程影响数据库,会发生什么情况 - 在这种情况下,repo1repo2 都会发生变化吗?

换句话说,想象一个像这样工作的 System.Console 实现。如果 Console.Out.WriteLine 始终返回一个新的不可变对象(immutable对象),那么它将如何与对 Console.In.ReadLine 的调用进行交互?

编辑 tl;dr: 不要这样做。有时副作用是好的。

关于.net - F# 中的存储库模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4305868/

相关文章:

.net - 如何从绝对路径获取相对路径

.net - 哪种数据验证方法最适合大型数据集

c# - 有利于性能

f# - 在 F# 中重载 [,] 运算符

c# - 无论如何都可以使用 F# 中的 C# 隐式运算符吗?

f# - 在 F# 中覆盖 ToString 时避免堆栈溢出

f# - 将两个变量传递到管道中

c# - 数据绑定(bind) : does not contain a property with the name 'CategoryId' error

F#:检查一个值是字符串数组、字符串数组还是字符串数组

.net - 从 .NET 为非原始数据类型调用旧的 C++ 函数