3

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

其次; 什么是能力类型。理想情况下,我想以 [Entity 能力 ID 能力] 结束。

最后; 如何将过滤器添加到上述连接中以便仅获得“用户”的权限?

4

2 回答 2

2

感谢 dflemstr 的(大量)帮助,我最终得到了

mmember <- runMaybeT $ do
  id <- MaybeT $ maybeAuth
  let user = entityVal id
  Entity memberId member <- MaybeT . runDB . getBy . UniqueMember . userEmail $ user
  let competenceStatement =
        Text.concat
        [ "SELECT ?? "
        , "FROM   competence,     user_competence "
        , "WHERE  competence.id = user_competence.competence_id "
        , "AND    ?             = user_competence.user_id"
        ]
  competences <- lift . runDB $ rawSql competenceStatement
                 [toPersistValue . entityKey $ id]
  return (member, competences :: [Entity Competence])
于 2012-07-20T19:37:40.573 回答
2

我已经告诉过你,由于SelectOneMany使用的类型别名可能不是归纳的,因此无法避免额外的类型签名。即你的代码试图比它应该的更多态,并且类型签名是限制这种多态性所必需的。

您可以通过“从不同角度”约束类型来避免使用巨大的签名,例如:

return (member, competences :: [(Entity User, [Entity UserCompetence])])

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

另外,我只是competences为你破坏了类型。哈!我希望这对你来说已经足够了。如果您想要直接进行多对多三表连接,以便您可以获得用户“拥有”的所有权限,那么由于潜在的 AST 开销,您无论如何都应该使用准备好的语句,因此请查看通用的原始 SQL 接口,它让你做"SELECT * FROM foo WHERE bar = ?" [filteredBarValue]你可能更习惯使用的传统;它没有提供与其他类型相同的类型安全性,persistent但我认为这是在您的情况下实现三表连接的最简单方法。

您可以User通过修改其结果的oneFilterMany类型来限制选择的 s OneFilterMany。像这样(没有测试过,但应该可以):

let join = (selectOneMany (UserCompetenceUser <-.) userCompetenceUser)
           { somFilterOne = [... filters for User ...] }
competences <- lift . runDB . runJoin $ join
于 2012-07-20T00:29:32.780 回答