Yesod/Постоянный индивидуальный запрос

Скажем, в Yesod/Persistent у меня настроены модели следующим образом:

User
    ident Text
    password Text Maybe
    UniqueUser ident
Question
    title Text
    asker UserId Eq

И у меня есть список Question, и я хотел бы получить соответствующий список User. Как мне это сделать?

Я думал о соединениях, но это один ко многим, а не один к одному (полагаю, это не имеет значения, но я бы хотел более простое решение). Выполнение соединения вручную также является вариантом, но я беспокоюсь о производительности - у меня есть

questions <- runDB $ selectList [QuestionTitle !=. ""] [LimitTo 10]
let askerIds = map (\(Entity _ q) -> questionAsker q) questions
askers <- sequence $ map (runDB . get) askerIds
let questionsAndAskers = zip questions askers

но я беспокоюсь об использовании runDB в map (не будет ли это делать отдельный запрос к базе данных для каждого пользователя?)

Есть ли лучший/более идиоматический способ добиться этого?


person li.davidm    schedule 22.02.2012    source источник
comment
Да, я думаю, справедливо предположить, что каждый раз, когда вы нажимаете runDB, будет выполняться другой запрос к базе данных.   -  person Dan Burton    schedule 22.02.2012


Ответы (2)


Я еще не проверял это, но я бы поместил все это внутрь runDB:

runDB $ selectList [QuestionTitle !=. ""] [LimitTo 10] >>= mapM (\qe@(Entity _ q) -> do
    asker <- get $ questionAsker q
    return (qe, asker))
person Michael Snoyman    schedule 22.02.2012
comment
Так что с постоянным будет N + 1 выбор вместо 1? - person Qrilka; 02.04.2013
comment
Да, как сформулировано. Если вы хотите иметь один запрос, вам нужно использовать соединения. Для этого я бы рекомендовал использовать esqueleto. - person Michael Snoyman; 02.04.2013
comment
Спасибо, esqeleto выглядит многообещающе - person Qrilka; 02.04.2013

Как насчет:

questions <- runDB $ selectList [QuestionTitle !=. ""] [LimitTo 10]
let askerIds = map (\(Entity _ q) -> questionAsker q) questions
askers <- runDB $ selectList [UserId <-. askerIds] []
let questionsAndAskers = zip questions askers

Похоже, что он должен один раз попасть в БД для пользователей.

person ozataman    schedule 22.02.2012
comment
Если я не ошибаюсь, вторую строку можно было бы написать let askersIds = map (questionAsker . entityVal) questions, что мне кажется более читаемым. - person ; 14.07.2012