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

geo*_*off 8 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
Run Code Online (Sandbox Code Playgroud)

和功能

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

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

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

得到球员名单; 但它根本与会话无关

pbr*_*bin 6

目前持久性的连接支持有限,我相信它只是SQL.

我有几个帮助我用于简单的情况.他们可以在这里找到.这不是一个真正的JOIN,它每个表选择一次,然后构建一个元组列表,表示"连接"行,每个元素都包含一个元素.

鉴于你的模型和助手,你应该做的事情如下:

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

    return $ joinTables3 gamingSessionPlayer gamingSessionTable sessions players tables

forM records $ \(session, player, table) -> do
    --
    -- ...
    --
Run Code Online (Sandbox Code Playgroud)

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

  • 我们支持1对多连接,并且它在SQL连接和应用程序连接方面都实现了,因此它可以用于SQL或NoSQL后端.现在它的文档很少,但希望很快就能解决. (7认同)
  • 我不认为在Haskell中进行连接,RDBMS应该首先做的事情,可以被认为是可接受的答案.特别是对于Haskell居住的世界/社区. (3认同)

uno*_*hoo 5

为了将来参考,对于 sql,您可以使用 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)
Run Code Online (Sandbox Code Playgroud)

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