重构Doobie数据库查询函数以移除不安全的.get调用
问题:移除DAO调用中的不安全
.get方法 DAO方法定义
ProductDao.getById(..): ConnectionIO[Option[Product]] InventoryDao.getById(..): ConnectionIO[Option[Inventory]]
待重构的原函数
你写的这个函数里有两处直接调用.get的不安全操作,会在对应字段为None时抛出异常:
def getInventoryLocation(...): IO[Either[String, Int]] = { (for { product <- EitherT.fromOptionF(ProductDao.getById(id).transact(xa), "product not found") inventory <- EitherT.fromOptionF((InventoryDao.getById(product.inventorySectionId.get)).transact(xa), "product not found") } yield inventory.location.get).value }
你尝试用map处理product.inventorySectionId但没成功,写法如下:
inventory <- EitherT.fromOptionF(( product.inventorySectionId.map(InventoryDao.getById()) ).transact(xa), "product not found")
问题出在product.inventorySectionId.map(InventoryDao.getById())返回的是Option[ConnectionIO[Option[Inventory]]],而不是ConnectionIO[Option[Inventory]],没法直接调用.transact(xa)。
解决方案
我们可以用EitherT.fromOption把每个Option字段转换成安全的EitherT步骤,彻底移除.get调用:
完整重构代码
def getInventoryLocation(...): IO[Either[String, Int]] = { (for { // 获取产品,不存在则返回错误 product <- EitherT.fromOptionF(ProductDao.getById(id).transact(xa), "product not found") // 检查产品的inventorySectionId,不存在则返回对应错误 sectionId <- EitherT.fromOption(product.inventorySectionId, "product has no inventory section id") // 用sectionId查询库存,不存在则返回错误 inventory <- EitherT.fromOptionF(InventoryDao.getById(sectionId).transact(xa), "inventory not found") // 检查库存的location,不存在则返回对应错误 location <- EitherT.fromOption(inventory.location, "inventory has no location") } yield location).value }
关键改动说明
- 处理
product.inventorySectionId:
用EitherT.fromOption替代.get,如果inventorySectionId是None,会直接返回指定的错误信息,不会抛出异常。 - 处理
inventory.location:
同样用EitherT.fromOption处理,确保location为None时也返回明确的错误,而非崩溃。 - 精准错误信息:
把原来统一的“product not found”拆分成不同场景的错误,更便于定位问题。
内容的提问来源于stack exchange,提问作者Blankman
相关产品推荐
相关产品推荐

