我一直在研究Persistent库与sql数据库的接口。假设我有一个包含食谱的数据库,包括Recipe,Ingredient和RecIng表。
我对(持续有限的)对持久性的理解使我相信我应该像这样定义表格:
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Recipe
title String
Ingredient
name String
RecIng
recId RecipeId
ingId IngredientId
quantity Int
|]
通过这种方式,可以使用Esqueleto来获取这些表之间的内部联接:
select $
from $ \(i `InnerJoin ` ri `InnerJoin` r) -> do
on (r ^. RecipeId ==. ri ^. RecIngIngId)
on (i ^. IngredientId ==. ri ^. RegIngRecId)
return (r, ri, i)
这将返回(Recipe,RecIng,Ingredient)的元组。
我真正想要的是一种查询导致以下结果的食谱的方法:
data Recipe = Recipe { title :: String
, ingredients :: [Ingredient]
}
data Ingredient = Ingredient { name :: String
, quantity :: Integer
}
除了定义一组额外的数据类型和转换元组之外,还有最佳做法吗?
答案 0 :(得分:7)
+1给Adam的评论,这是正确的答案IMO。
您可能采取的单独方法是使用嵌入式实体,这实际上意味着JSON编码每个配方中的成分列表。但这将是糟糕的SQL设计,会导致更新的表锁定问题,并且不能很好地扩展大量的成分。
换句话说,您希望使用的Haskell表示与在数据库中存储数据的正确方法之间存在不匹配。这并不意味着数据库格式或Haskell数据类型存在问题:这是一个逻辑上的差异。对这一差距的正确回应是有两种数据类型和一种智能方式在它们之间进行转换。