2012-03-19 14 views
8

Considerare i modelli:modo corretto di fare un "join" a persistere con 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 

e la funzione

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

come si potrebbe fare per ottenere tutti i nomi dei giocatori per ognuna delle le sessioni associate?

facendo

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

ottiene la lista dei giocatori; ma non è associato a tutte le sessioni

risposta

6

In questo momento è disponibile un supporto di join limitato, e credo che sia solo SQL.

Ho un paio di helper che uso per casi semplici. Possono essere trovati here. Non è un vero JOIN, seleziona una volta per tabella quindi crea un elenco di tuple che rappresentano le righe "unite" con un elemento di ciascuna.

dato i vostri modelli e che aiutante, si dovrebbe in grado di fare qualcosa di simile:

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

    return $ joinTables3 gamingSessionPlayer gamingSessionTable sessions players tables 

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

Solo i casi in cui esiste un record in tutte e tre le tabelle saranno restituiti (quindi è un INNER JOIN), ma si potrebbe vuoi pre-filtrare anche per l'efficienza.

+7

Abbiamo il supporto per un join 1-to-many, ed è implementato sia in termini di join di SQL che di join di un'applicazione, quindi può funzionare sia per SQL o backend NoSQL. È scarsamente documentato in questo momento, ma spero che possa essere affrontato presto. –

+1

Non penso che fare un join in Haskell, cosa che un RDBMS dovrebbe fare in primo luogo, può essere considerato una risposta accettabile. Soprattutto per il mondo/comunità che Haskell abita. –

2

Per riferimento futuro, per SQL è possibile utilizzare esqueleto o rawSQL fare unisce - vedere questa risposta Baffled by selectOneMany in Yesod

Se si voleva utilizzare un join, in Esqueleto la query sarebbe simile:

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

Ciò restituirebbe una tuple (Entity GamingSession, PlayerId)

Problemi correlati