假设一个简单的1 - >模型中的N关系。
我想渲染一个表,其中包含来自主实体的数据行和依赖实体的聚合函数(N),无论是sum,avg,max还是custom。
我一直在尝试几十个处理程序,但没有找到任何编译器......
任何提示?
示例:
实体A
Key Value
a b
c d
e f
实体B
ForeignKey Num Value
a 1 13.0
a 2 25.4
a 3 10.2
c 1 33.33
c 2 50.0
e 1 100.0
e 2 1000.0
并希望从相同的“html行”中获取A中的值和来自B的值,其中包含最大数量
b 10.2
d 50.0
f 1000.0
答案 0 :(得分:2)
我不确定您已尝试过什么,但由于这实际上是一个连接(并且持久性的类型安全API不支持它们),因此运行自定义SQL查询应该是最有效的解决方案。如果您的模型看起来像这样
EntityA
key Text
value Text
deriving Show
EntityB
foreignKey EntityAId
num Int
value Double
deriving Show
使用max
函数加入数据的查询看起来像这样:
SELECT a.value, max(b.num), b.value
FROM entity_a a LEFT OUTER JOIN entity_b b
ON a.id = b.foreign_key
GROUP BY (a.id);
将它与rawSql函数相结合应该可以解决问题。
但是,如果您希望使用持久性类型安全的API来执行此操作,则可能会导致对数据库进行大量查询,具体取决于数据的大小。这是它的样子:
-- a custom maximum function for EntityB
customFunction :: [EntityB] -> Maybe EntityB
customFunction = foldr customFold Nothing
customFold :: EntityB -> Maybe EntityB -> Maybe EntityB
customFold a Nothing = Just a
customFold a (Just b) = if (entityBNum a) > (entityBNum b) then (Just a) else (Just b)
main :: IO ()
main = runSqlite ":memory:" $ do
runMigration migrateAll
-- insert some data
firstAId <- insert $ EntityA "a" "b"
secondAId <- insert $ EntityA "c" "d"
thirdAId <- insert $ EntityA "e" "f"
-- let's put this one just for demonstration
fourthAId <- insert $ EntityA "g" "h"
bId1 <- insert $ EntityB firstAId 1 13.0
bId2 <- insert $ EntityB firstAId 2 25.4
bId3 <- insert $ EntityB firstAId 3 10.2
bId4 <- insert $ EntityB secondAId 1 33.33
bId5 <- insert $ EntityB secondAId 2 50.0
bId6 <- insert $ EntityB thirdAId 1 100.0
bId7 <- insert $ EntityB thirdAId 2 1000.0
-- select all EntityA's
as <- selectList [] [Asc EntityAId]
-- aKeys are used as foreign keys for EntityB's
let aKeys = map entityKey as
-- these values will be used for "joining" data together
aVals = map (entityAValue . entityVal) as
-- this will produce a number of queries which is
-- equal to a number of groups (in your simple case, 3)
bs <- mapM (\bKey -> selectList [EntityBForeignKey ==. bKey] []) aKeys
-- extract what's needed from a list of lists of EntityB's
let bEntities = map (customFunction . (map entityVal)) bs
-- ... and zip them together
joined = zip aVals bEntities
liftIO $ print joined
我得到的这段代码的输出是:
[("b",Just (EntityB {entityBForeignKey = Key {unKey = PersistInt64 1}, entityBNum = 3, entityBValue = 10.2})),("d",Just (EntityB {entityBForeignKey = Key {unKey = PersistInt64 2}, entityBNum = 2, entityBValue = 50.0})),("f",Just (EntityB {entityBForeignKey = Key {unKey = PersistInt64 3}, entityBNum = 2, entityBValue = 1000.0})),("h",Nothing)]
在你的问题中提取表并将其放入Handler monad应该很简单。
我知道这不是最好看的代码片段,但是比较这里显示的两种方法可能对你有用。