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