我试图让selectOneMany取得有限的成功。
我有以下数据库模型
User
email Text
verkey Text Maybe
verified Bool
password Text Maybe
UniqueUser email
date UTCTime
deriving Show
Competence
parent CompetenceId Maybe
title Text
UniqueCompetence title
deriving Show Read
UserCompetence
competence CompetenceId
user UserId Eq
UniqueUserCompetence user competence
deriving Show Read
来自我的处理程序的代码
mmember <- runMaybeT $ do
id <- MaybeT $ maybeAuth
user <- MaybeT . runDB . get . entityKey $ id
Entity memberId member <- MaybeT . runDB . getBy . UniqueMember . userEmail $ user
competences <- lift . runDB . runJoin $ (selectOneMany (UserCompetenceUser <-.) userCompetenceUser)
return (member,competences)
首先;我不能让事件运行该代码而不添加大的类型签名,这是应该的吗?
competences <- lift . runDB . runJoin $ (selectOneMany (UserCompetenceUser <-.) userCompetenceUser :: SelectOneMany SqlPersist (UserGeneric SqlPersist) (UserCompetenceGeneric SqlPersist))
其次;能力是什么类型。理想情况下,我想结束于[实体能力ID能力]。
最后;如何将过滤器添加到上述联接中,以便仅获得“用户”的能力?
最佳答案
我已经告诉过您,由于SelectOneMany
使用可能不是归纳的类型别名,因此无法避免额外的类型签名。也就是说,您的代码会尝试将其多态性提高到应有的水平,并且必须使用类型签名来限制该多态性。
您可以通过“从另一个角度”限制类型来避免使用巨大的签名,例如:
return (member, competences :: [(Entity User, [Entity UserCompetence])])
由于类型别名
User
和UserCompetence
选择特定的数据库后端,因此应适当解析类型。另外,我只是为您破坏了
competences
的类型。哈哈!我希望这足以满足您的需求。如果您希望直接进行多对多三表联接,以便获得用户“拥有”的所有能力,则由于潜在的AST开销,无论如何都应使用准备好的语句,因此请查看the generic raw SQL interface做您可能更习惯使用的传统"SELECT * FROM foo WHERE bar = ?" [filteredBarValue]
;它没有提供与persistent
其余部分相同的类型安全性,但是我认为这是在您的情况下实现三表联接的最简单方法。您可以通过修改类型为
User
的oneFilterMany
结果来限制选择的OneFilterMany
。像这样(尚未测试,但应该可以工作):let join = (selectOneMany (UserCompetenceUser <-.) userCompetenceUser)
{ somFilterOne = [... filters for User ...] }
competences <- lift . runDB . runJoin $ join