Правильный способ сделать "соединение" в сохранении с Yesod - PullRequest
8 голосов
/ 20 марта 2012

Рассмотрим модели:

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 ]

6 голосов
/ 20 марта 2012

В настоящее время существует ограниченная поддержка объединений, и я считаю, что это только SQL.

У меня есть пара помощников, которые я использую для простых случаев.Их можно найти здесь .Это не настоящий JOIN, он выбирает один раз для каждой таблицы, а затем создает список кортежей, представляющих «соединенные» строки с элементами из каждого.

Учитывая ваши модели и этого помощника, вы должны иметь возможность сделать что-то вроде:

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

    return $ joinTables3 gamingSessionPlayer gamingSessionTable sessions players tables

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

Будут возвращены только те случаи, когда запись существует во всех трех таблицах (так что это ВНУТРЕННЕЕ СОЕДИНЕНИЕ), но вам может потребоваться предварительная фильтрация для эффективности.

3 голосов
/ 18 июля 2014

Для дальнейшего использования, для 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)

...