2012-03-19 13 views
8

Considere los modelos:forma correcta de hacer un "unirse" en persistir 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 

y la función

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

cómo uno va sobre conseguir todos los nombres del jugador para cada uno de las sesiones asociadas?

haciendo

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

obtiene la lista de jugadores; pero no está asociado con las sesiones en absoluto

Respuesta

6

Hay soporte de unión limitado persistente en este momento, y creo que solo es SQL.

Tengo un par de ayudantes que utilizo para casos simples. Se pueden encontrar here. No es un JOIN verdadero, selecciona una vez por mesa y luego crea una lista de tuplas que representan filas "unidas" con un elemento de cada una. serán devueltos

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

    return $ joinTables3 gamingSessionPlayer gamingSessionTable sessions players tables 

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

Sólo los casos en los que existe un registro en las tres tablas (por lo que es un INNER JOIN), pero es posible:

Dadas sus modelos y que ayudante, usted debe poder hacer algo como también quiere prefiltrar por eficiencia.

+7

Tenemos soporte para una unión 1-to-many, y se implementa tanto en términos de una combinación de SQL y una aplicación, por lo que puede funcionar para SQL o backends NoSQL. Está mal documentado en este momento, pero espero que pueda abordarse pronto. –

+1

No creo que hacer una unión en Haskell, algo que un RDBMS debería estar haciendo en primer lugar, puede considerarse una respuesta aceptable. Especialmente, para el mundo/comunidad que habita Haskell. –

2

Para referencia futura, para SQL puede utilizar esqueleto o rawSQL hacer une - ver esta respuesta Baffled by selectOneMany in Yesod

Si desea utilizar una combinación, en el esqueleto de su consulta sería algo como:

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

Esto devolvería una tupla (Entity GamingSession, PlayerId)

Cuestiones relacionadas