Правильный способ сделать "соединение" в сохранении с 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)

Другие вопросы по тегам