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))

第二に; コンピテンシーの種類は何ですか。理想的には、[エンティティコンピテンシーIDコンピテンシー]で終わりたいです。

最後に、'user'のコンピテンシーのみを取得するために、上記の結合にフィルターを追加するにはどうすればよいですか?

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])])

タイプはエイリアスUserでありUserCompetence、特定のデータベースバックエンドを選択するため、タイプは適切に解決される必要があります。

また、私はあなたのためにタイプを台無しにしましたcompetences。はぁ!それで十分だと思います。多対多の3テーブル結合を直接実行して、ユーザーがすべてのコンピテンシーを「所有」できるようにする場合は、ASTオーバーヘッドが発生する可能性があるため、とにかくプリペアドステートメントを使用する必要があります"SELECT * FROM foo WHERE bar = ?" [filteredBarValue]作業に慣れている可能性のある従来の方法を実行できます。他の部分と同じタイプの安全性は提供されませんが、persistent3つのテーブルの結合を実装する最も簡単な方法だと思います。

タイプがUserの結果を変更することにより、選択されるを制限できます。そのように(まだテストしていませんが、動作するはずです):oneFilterManyOneFilterMany

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