2012-03-19 35 views
8

Hãy xem xét các mô hình:cách đúng để làm một "tham gia" trong kiên trì với 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 

và chức năng

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

thế nào người ta sẽ đi về nhận được tất cả các tên Player cho mỗi người trong số các phiên liên quan?

làm

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

nhận được danh sách các cầu thủ; nhưng nó không được liên kết với các phiên tại tất cả

Trả lời

6

Có hỗ trợ tham gia hạn chế liên tục tại thời điểm này và tôi tin rằng đó là chỉ SQL.

Tôi có một số người trợ giúp mà tôi sử dụng cho các trường hợp đơn giản. Họ có thể được tìm thấy here. Nó không phải là một JOIN thực sự, nó chọn một lần cho mỗi bảng sau đó xây dựng một danh sách các bộ dữ liệu đại diện cho các hàng "nối" với một phần tử từ mỗi hàng.

Với mô hình của bạn và rằng helper, bạn nên có thể làm một cái gì đó như:

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

    return $ joinTables3 gamingSessionPlayer gamingSessionTable sessions players tables 

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

Chỉ trường hợp một kỷ lục tồn tại trong tất cả ba bảng sẽ được trả lại (vì vậy nó là một INNER JOIN), nhưng bạn có thể cũng muốn lọc trước hiệu quả.

+7

Chúng tôi có hỗ trợ tham gia 1 đến nhiều và được triển khai cả về tham gia SQL và tham gia ứng dụng, vì vậy nó có thể hoạt động cho cả SQL hoặc chương trình phụ trợ NoSQL. Hiện tại nó đã được ghi nhận kém, nhưng hy vọng rằng nó có thể được giải quyết sớm. –

+1

Tôi không nghĩ rằng làm một tham gia trong Haskell, một cái gì đó mà một RDBMS nên được làm ở nơi đầu tiên, có thể được coi là một câu trả lời chấp nhận được. Đặc biệt, đối với thế giới/cộng đồng mà Haskell sinh sống. –

2

Để tham khảo trong tương lai, cho sql bạn có thể sử dụng esqueleto hoặc rawSQL khi kết bảng - xem câu trả lời này Baffled by selectOneMany in Yesod

Nếu bạn muốn sử dụng một tham gia, trong esqueleto truy vấn của bạn sẽ giống như thế:

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

Điều này sẽ trả về một bộ (Entity GamingSession, PlayerId) tuple