如果我们在模型文件中定义了2个简单对象,例如: -
Person
name Text
Age Int
Book
title Text
author Text
Run Code Online (Sandbox Code Playgroud)
我们可以为Book定义一个适用表格: -
addBookForm = renderDivs $ Book
<$> areq textField "title" Nothing
<*> areq textField "author" Nothing
Run Code Online (Sandbox Code Playgroud)
但是,如果我们想要将作者从一个文本字段更改为一个人的id,则:
Book
title Text
author PersonId
Run Code Online (Sandbox Code Playgroud)
然后上面的表格将无法编译,出现此错误: -
Couldn't match expected type `KeyBackend Database.Persist.GenericSql.Raw.SqlBackend Person' with actual type `Text'
Expected type: Field
sub0
master0
(KeyBackend Database.Persist.GenericSql.Raw.SqlBackend Person)
Actual type: Field sub0 master0 Text
In the first argument of `areq', namely `textField'
In the second argument of `(<*>)', namely
`areq textField "author" Nothing'
Run Code Online (Sandbox Code Playgroud)
我们现在如何定义作者字段?我们需要使用monadic形式吗?
谢谢 !
错误消息表示您尝试使用Text(来自字段结果)作为Key.
您可以使用checkMMap包装textField并修改结果:
addBookForm = renderDivs $ Book
<$> areq textField "title" Nothing
<*> (entityKey <$> areq authorField "author" Nothing)
where
authorField = checkMMap findAuthor (personName . entityVal) textField
findAuthor name = do
mperson <- runDB $ selectFirst [PersonName ==. name] []
case mperson of
Just person -> return $ Right person
Nothing -> return $ Left ("Person not found." :: Text)
Run Code Online (Sandbox Code Playgroud)
该findAuthor函数获取简单,如果你添加一个独特的构造函数的Person领域:
Person
name Text
...
UniquePerson name
Run Code Online (Sandbox Code Playgroud)
然后selectFirst ...你可以做而不是
mperson <- runDB $ getBy $ UniquePerson name
Run Code Online (Sandbox Code Playgroud)