Правильный способ сделать "соединение" в сохранении с 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 ответа
В настоящее время существует ограниченная поддержка объединений, и я считаю, что это только SQL.
У меня есть пара помощников, которых я использую для простых дел. Их можно найти здесь. Это не настоящий JOIN, он выбирает один раз для каждой таблицы, а затем создает список кортежей, представляющих "соединенные" строки с элементами из каждой.
Учитывая ваши модели и этого помощника, вы должны сделать что-то вроде:
records <- runDB $ do
sessions <- selectList [] []
players <- selectList [] []
tables <- selectList [] []
return $ joinTables3 gamingSessionPlayer gamingSessionTable sessions players tables
forM records $ \(session, player, table) -> do
--
-- ...
--
Будут возвращены только те случаи, когда запись существует во всех трех таблицах (так что это ВНУТРЕННЕЕ СОЕДИНЕНИЕ), но вам может потребоваться предварительная фильтрация для эффективности.
Для дальнейшего использования, для sql вы можете использовать esqueleto или rawSQL для выполнения объединений - см. Этот ответ , озадаченный selectOneMany в 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)