我正在尝试使用 cached
函数来防止不同小部件和处理程序中的多个数据库查询:
newtype CachedBobId key
= CachedBobId { unCachedBobId :: key }
deriving Typeable
getBob' :: Handler BobId
getBob' = do
uncle <- runInputGet $ ireq textField "bobsuncle"
(Entity bob _) <- runDB $ getBy404 $ UniqueBob uncle
return bob
getBob :: Handler BobId
getBob = do
a <- getBob'
let b = return $ CachedBobId a
c <- cached b
return $ unCachedBobId c
在某个小部件中:
renderDerp :: Widget
renderDerp = do
--these are used in the shakespeare files
lolBob <- handlerToWidget $ getBob
nutherBob <- handlerToWidget $ getBob
$(widgetFile "test")
这可以编译,但获取 ID 的查询仍然运行多次。
我做错了什么?或者是否有更好的方法只获取 bob 一次并在每个处理程序和小部件中使用他?
最佳答案
我对 Yesod 还很陌生,但我认为你只需要调整 getBob
getBob :: Handler BobId
getBob = unCachedBobId <$> cached (CachedBobId <$> getBob')
问题是您当前的 getBob
函数开始其 do
阻止 a <- getBob'
。请记住 do
block 序列单子(monad) Action ,所以你实际上最终调用 getBob'
每次第一件事getBob
叫做。具有讽刺意味的是,完成此操作后,您将创建一个处理程序的缓存版本,该处理程序返回您刚刚从 getBob'
获得的内容。 ,但最终只查询该缓存版本一次(随后使用 c <- cached b
),然后它就超出了范围,垃圾收集器得到了它。
在我上面介绍的解决方案中,您可以包装任何 getBob'
给你CachedBobId
。然后,您传递该处理程序 CachedBobId <$> getBob' :: Handler (CachedBobId BobId)
, 至cached
,它会返回另一个处理程序 cached (CachedBobId <$> getBob')
类型相同,但带有缓存。最后,您提取缓存处理程序提供的任何内容以获取 Handler BobId
.
关于haskell - 如何使用 yesod 按请求缓存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33655589/