使用yesod持续执行“加入”的正确方法

时间:2012-03-19 23:06:22

标签: haskell persistent yesod

考虑模型:

Player
    name Text
    nick Text
    email Text Maybe
    phone Text Maybe
    note Textarea Maybe
    minutes Int Maybe
    deriving

Table
    name Text
    game Text
    pointsHour Int
    seats Int Maybe
    description Text Maybe
    deriving

GamingSession
    start UTCTime
    end UTCTime Maybe
    player PlayerId
    table TableId
    seat Int Maybe
    deriving

和功能

getGamingSessionsR :: Handler RepHtml
getGamingSessionsR = do
  sessions <- runDB $ selectList [GamingSessionEnd ==. Nothing] [Desc GamingSessionTable]
  defaultLayout $(widgetFile ("opensessions"))

如何获得每个相关会话的所有播放器名称?

操作

players <- runDB $ selectList [FilterOr . map (\(Entity _ s) -> PlayerId ==. (GamingSessionPlayer s)) $ sessions] []

获取玩家名单;但它与所有会议无关

2 个答案:

答案 0 :(得分:6)

此时持久性的连接支持有限,我相信它只是SQL。

我有几个帮助我用于简单的案例。他们可以找到here。这不是一个真正的JOIN,它每个表选择一次,然后构建一个元组列表,表示“连接”行,每个元素都有一个元素。

鉴于您的模型和助手,您应该能够执行以下操作:

records <- runDB $ do
    sessions <- selectList [] []
    players  <- selectList [] []
    tables   <- selectList [] []

    return $ joinTables3 gamingSessionPlayer gamingSessionTable sessions players tables

forM records $ \(session, player, table) -> do
    --
    -- ...
    --

只有在所有三个表中都存在记录的情况才会被返回(因此它是一个内部联接),但您可能也希望对效率进行预过滤。

答案 1 :(得分:3)

为了将来参考,对于s​​ql,您可以使用esqueleto或rawSQL进行连接 - 请参阅此答案Baffled by selectOneMany in Yesod

如果您想使用联接,请在esqueleto中查询类似于:

select $ from $ \(gamingSession `InnerJoin` player) -> do 
    on (gamingSession ^. GamingSessionPlayer ==. player ^. PlayerId)
    where_ $ isNothing $ gamingSession ^. GamingSessionEnd
    orderBy [asc (gamingSession ^. GamingSessionTable)] 
    return (gamingSession, player ^. PlayerId)

这将返回(Entity GamingSession,PlayerId)元组