SQL 具有 ROP 的类型提供程序 - F#
SQL Type Providers with ROP - F#
我正在尝试使用面向铁路的编程原则http://fsharpforfunandprofit.com/rop/ and this http://indiedevspot.azurewebsites.net/2015/01/20/two-track-coding-rop-for-dummies-part-2/作为参考
我已经为大部分代码库成功实现了这一点,除了现在我们要将项目放入 SQL 并希望使用 ROP 来验证这些类型。典型的模式是
图一:
let createSomething a b c = {A = a; B = b; C = c}
let createValidSomething so =
createSomething
<!> validateFunction1 so.param1
<*> validateFunction2 so.param2
<*> ...so forth and so on
你会注意到 createSomething 是一个 returns 记录类型实例化 a -> b -> c -> a' -> b' -> c' 的函数
SQL 类型提供者 return 可变类型(非记录)。让我们看看我尝试构建一个类似的 createSomething 函数
图二:
let createSQS(a, b, c, d, e, f, g) =
let sqs = context.``[dbo].[Something]``.Create(a, b, c, d, e, f, g)
sqs
此时,我们知道这已经行不通了,我们有 a->b->c->d->e->f->g->context.[dbo].[Something]
.Entity
我知道我可以有一个中间记录类型并遵循 ROP 原则,在 success/failure 上匹配,然后从已经验证的对象中创建我的对象。但这似乎不是太多步骤吗?
有人知道一个好的模式吗?理想情况下,我们可以使用类似于图 1 的函数来生成与类型提供程序兼容的记录类型。
我乐于尝试并在 Skype 上闲逛 :)。
你的函数 createSQS
不应该像这样更好吗:
let createSQS a b c d e f g =
context.``[dbo].[Something]``.Create(a, b, c, d, e, f, g)
这个将具有 a->b->c->d->e->f->g->context.[dbo].[Something].Entity
所需的签名
所以我们在开发会议上得出了一个答案,并决定我们实际上想要在其自己的函数中执行每个部分。对于内部绑定,我们发明了自己的运算符;类似于加号 (&&&)(我将在我的网站 www.indiedevspot.com 上写博客)并且在顶层我们 运行 具有正常绑定。
我们的顶级代码如下所示:
[<HttpPost>]
x.member Add(sa:Something) =
sa|>ValidateSomething
>>= converttoSSA
>>= persistSSA
由于验证、转换和持久性的独立可测试性,我们决定将关注点分开。该理论认为,如果函数组合由保证 运行 可以工作的函数组成,那么它本身就可以保证 运行 可以工作(或者有更好的机会)。
如果我们采用提议的方法(我们尚未解决),我们将混合创建、验证和转换的问题。这也将最终创建一个额外的记录类型,即 un-necessary.
我正在尝试使用面向铁路的编程原则http://fsharpforfunandprofit.com/rop/ and this http://indiedevspot.azurewebsites.net/2015/01/20/two-track-coding-rop-for-dummies-part-2/作为参考
我已经为大部分代码库成功实现了这一点,除了现在我们要将项目放入 SQL 并希望使用 ROP 来验证这些类型。典型的模式是
图一:
let createSomething a b c = {A = a; B = b; C = c}
let createValidSomething so =
createSomething
<!> validateFunction1 so.param1
<*> validateFunction2 so.param2
<*> ...so forth and so on
你会注意到 createSomething 是一个 returns 记录类型实例化 a -> b -> c -> a' -> b' -> c' 的函数 SQL 类型提供者 return 可变类型(非记录)。让我们看看我尝试构建一个类似的 createSomething 函数
图二:
let createSQS(a, b, c, d, e, f, g) =
let sqs = context.``[dbo].[Something]``.Create(a, b, c, d, e, f, g)
sqs
此时,我们知道这已经行不通了,我们有 a->b->c->d->e->f->g->context.[dbo].[Something]
.Entity
我知道我可以有一个中间记录类型并遵循 ROP 原则,在 success/failure 上匹配,然后从已经验证的对象中创建我的对象。但这似乎不是太多步骤吗?
有人知道一个好的模式吗?理想情况下,我们可以使用类似于图 1 的函数来生成与类型提供程序兼容的记录类型。
我乐于尝试并在 Skype 上闲逛 :)。
你的函数 createSQS
不应该像这样更好吗:
let createSQS a b c d e f g =
context.``[dbo].[Something]``.Create(a, b, c, d, e, f, g)
这个将具有 a->b->c->d->e->f->g->context.[dbo].[Something].Entity
所以我们在开发会议上得出了一个答案,并决定我们实际上想要在其自己的函数中执行每个部分。对于内部绑定,我们发明了自己的运算符;类似于加号 (&&&)(我将在我的网站 www.indiedevspot.com 上写博客)并且在顶层我们 运行 具有正常绑定。
我们的顶级代码如下所示:
[<HttpPost>]
x.member Add(sa:Something) =
sa|>ValidateSomething
>>= converttoSSA
>>= persistSSA
由于验证、转换和持久性的独立可测试性,我们决定将关注点分开。该理论认为,如果函数组合由保证 运行 可以工作的函数组成,那么它本身就可以保证 运行 可以工作(或者有更好的机会)。
如果我们采用提议的方法(我们尚未解决),我们将混合创建、验证和转换的问题。这也将最终创建一个额外的记录类型,即 un-necessary.