这个问题是关于groundhog
or persistent
,因为我相信两者都有相同的问题。
假设我有一个Tr m a
提供一些功能的变压器f :: Int -> Tr m ()
。此功能需要数据库访问。我可以在这里使用一些选项,但没有一个是令人满意的。
我可以DbPersist
在里面的某个地方放一个变压器Tr
。实际上,我需要将它放在顶部,因为没有PersistBackend
标准转换器的实例,而且我仍然需要为我的新类型编写一个实例Tr
。这已经很糟糕了,因为课程远非最小。我也可以解除我所做的每一个 db 操作。
另一种选择是更改f
to的签名PersistBackend m => Int -> Tr m ()
。这将再次需要PersistBackend
我的Tr
newtype 上的实例或提升。
现在这是真正的问题。如何Tr
在已经有PersistBackend
约束的上下文中运行?没有办法与它分享Tr
。
我可以执行第一个选项并使用一些新的连接池DbPersist
在其中运行实际的转换Tr
器(据我所知,无法从PersistBackend
我已经在其中的上下文中获取池),或者我可以执行第二个选项并具有运行功能runTr :: PersistBackend m => Tr m a -> m a
。第二个选项实际上完全没问题,但这里的问题是,DbPersist
最终必须在堆栈中的某个位置,现在位于Tr
变压器下方,并且没有PersistBackend
标准变压器的实例Tr
。
这里的正确方法是什么?目前看来,最好的选择是ReaderT
在堆栈中的某个地方使用一个分隔符,根据请求为我提供连接池,然后runDbConn
在我想访问数据库的任何地方使用该池。看到DbPersist
基本上已经只是一个ReaderT
我不明白必须这样做的意义。