我试图让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])])


由于类型别名UserUserCompetence选择特定的数据库后端,因此应适当解析类型。

另外,我只是为您破坏了competences的类型。哈哈!我希望这足以满足您的需求。如果您希望直接进行多对多三表联接,以便获得用户“拥有”的所有能力,则由于潜在的AST开销,无论如何都应使用准备好的语句,因此请查看the generic raw SQL interface做您可能更习惯使用的传统"SELECT * FROM foo WHERE bar = ?" [filteredBarValue];它没有提供与persistent其余部分相同的类型安全性,但是我认为这是在您的情况下实现三表联接的最简单方法。

您可以通过修改类型为UseroneFilterMany结果来限制选择的OneFilterMany。像这样(尚未测试,但应该可以工作):

let join = (selectOneMany (UserCompetenceUser <-.) userCompetenceUser)
           { somFilterOne = [... filters for User ...] }
competences <- lift . runDB . runJoin $ join

07-26 00:59