3

从一个人为config/models的脚手架网站:

Inventory
  name        Text
  description Text
Container
  name        Text
ContainerSlot
  container   ContainerId
  item        InventoryId Maybe

现在,使用 Esqueleto,我想用来LeftOuterJoin获取容器中的插槽,如果尚未分配实际库存,则实际库存为空。

selectContainerSlots containerKey = do
  stuff <- select $ from $ \(cs `LeftOuterJoin` i) -> do
    on $ cs ^. ContainerSlotItem ==. just (i ^. InventoryId)
    where_ $ cs ^. ContainerSlotContainer ==. val containerKey
    return (cs, i)
  return $ uncurry buildStuff <$> stuff

buildStuff由于联接的“外部”性质,我希望需要以下签名:

buildStuff :: Entity ContainerSlot -> Maybe (Entity Inventory) -> Result

但发现它需要以下内容:

buildStuff :: Entity ContainerSlot -> Entity Inventory -> Result

Inventory当(可预测地)字段填充有NULL值时,这会导致运行时失败。

PersistMarshalError "field id: int64 Expected Integer, received: PersistNull"

有没有办法将Entity Inventoryas投影到Maybe (Entity Inventory)?

4

1 回答 1

2

这可能被标记为Outer Joins with Esqueleto的副本;但是不同之处在于投影。

在处理任何外连接时,所有可能返回 null 的表都应该使用语法完成所有投影。?.这将迫使表的实体成为Maybe (Entity a)所以上面的解决方案是

selectContainerSlots containerKey = do
  stuff <- select $ from $ \(cs `LeftOuterJoin` i) -> do
    on $ cs ^. ContainerSlotItem ==. i ?. InventoryId
    where_ $ cs ^. ContainerSlotContainer ==. val containerKey
    return (cs, i)
  return $ uncurry buildStuff <$> stuff

此外,如果链接了多个表;例如

select $ from $ \(cs `LeftOuterJoin` (i `InnerJoin` is)) -> do

然后 iis库存 SKU 表)都应该使用该语法进行投影:

  on $ i ?. InventoryId ==. is ?. InventorySkuItem
  on $ cs ^. ContainerSlotItem ==. i ?. InventoryId
于 2017-04-02T03:19:56.543 回答