How to use yesod per

I'm trying to use the cached function to prevent multiple db queries in different widgets and handlers:

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

And in a widget somewhere:

renderDerp :: Widget
renderDerp = do
    --these are used in the shakespeare files
    lolBob <- handlerToWidget $ getBob
    nutherBob <- handlerToWidget $ getBob
    $(widgetFile "test")

This compiles but the query to get the ID still runs multiple times.

What am I doing wrong? Or is there a better way to only get bob once and use him in every handler and widget?


I'm pretty new to Yesod, but I think you just need to tweak getBob

getBob :: Handler BobId
getBob = unCachedBobId <$> cached (CachedBobId <$> getBob')

The problem is that your current getBob function starts its do block with a <- getBob' . Remember that a do block sequences monadic actions, so you actually end up calling getBob' first thing every time getBob is called. In an ironic twist, after you've done this, you create a cached version of a handler which returns what you just got from getBob' , but end up querying that cached version exactly once (right afterwards with c <- cached b ), then it just falls out of scope and the garbage collector gets it.

In the solution I present above, you wrap whatever getBob' gives you in CachedBobId . Then, you pass that handler CachedBobId <$> getBob' :: Handler (CachedBobId BobId) , to cached , which gives you back another handler cached (CachedBobId <$> getBob') of the same type, but with caching. Finally, you extract whatever the cached handler gives you to get back a Handler BobId .

链接地址: http://www.djcxy.com/p/30306.html

上一篇: 张量流中的条件图和访问张量大小的循环

下一篇: 如何使用yesod