我即将在Lift框架中开始我的第一个项目,我必须决定选择哪个持久性库。我即将使用关系后端,因此Mapper和Record都可以发挥作用。
在Mapper的情况下 - 我最想念的是能够控制发送到RDBMS的查询 - 特别是当涉及更复杂的查询时,这些查询将通过SQL中的连接,聚合等来解决。举几个例子 - 让我们有两个实体:
class BaseProduct extends LongKeyedMapper[BaseProduct] with IdPK {
// some fields
}
object BaseProduct extends BaseProduct with LongKeyedMetaMapper[BaseProduct]
class MyProduct extends LongKeyedMapper[MyProduct] with IdPK {
// some fields
object base extends MappedLongForeignKey(this, BaseProduct)
}
object MyProduct extends MyProduct with LongKeyedMetaMapper[MyProduct]
MyProduct
是BaseProduct
实体的特化之一。这些实体之间显然存在一对一的关系。不过,我提出的查询确切MyProduct
及其BaseProduct
的最佳可能性是这样的查询:
MyProduct.findAll(PreCache(MyProduct.base))
哪个会发出两个查询(而且我恐怕无法控制我要选择的MyProduct
实体的哪些字段。
Mapper库足够糟糕。我对Record / Squeryl API的主要关注是它缺少Mapper API周围存在的所有Proto
类。是否有一些接近这些类的功能的记录?是否可以访问Squeryl中的数据库特定功能(例如PostgreSQL中的几何查询)?
这些图层中是否还有其他优缺点?或者是否有任何其他抽象层,如果我想要与数据库进行通信的良好类型安全封装并且可以提供对查询的良好控制(我习惯于使用PHP中的PDO层直接发出查询 - 我是值得注意的 - 我不想要这样的直接查询界面,但是控制查询的可能性很大。与Lift框架的集成绝对是一个优势。
谢谢!
答案 0 :(得分:5)
我们一直在使用Squeryl和Lift很长一段时间,并对它非常满意。根据您的上述情况,在当前版本的Squeryl(0.9.5)中,您可以执行以下操作:
class BaseProduct(id:Long, some more fields) extends KeyedEntity[Long] {
}
class MyProduct(id:Long, some more fields) extends KeyedEntity[Long] {
}
然后,您将拥有一个定义relationships的模式(我假设它们已加入ID字段):
val baseProducts = Table[BaseProduct]("base_products")
val myProducts = Table[MyProduct]("my_products")
val myProductsToBaseProducts =
oneToManyRelation(myProducts, baseProducts).via((mp, bp) =>
mp.id === bp.id)
要查询两个记录,您可以执行以下操作:
from(myProducts, baseProducts) ( (mp, bp) =>
where(mp.id === bp.id and mp.id === LOOKUPVAL)
select(bp, mp) )
上面的查询将从单个SQL select中返回(BaseProduct,MarketProduct)元组。
您还可以使用该关系来检索相关项,例如将此方法添加到MyProduct
:
def baseProduct = myProductsToBaseProducts.left(this)
但是,与Mapper中的示例一样,它将发出第二个查询。至于创建特定于数据库的查询,有&
运算符,它允许您在服务器上计算表达式。如果Squeryl中没有该功能,您可以创建custom functions。
总的来说,我发现Squeryl非常灵活,是ORM和直接SQL之间的完美混合体。它表现非常好,我没有找到太多地方,Squeryl禁止我轻易获得我需要的数据库功能。使用下一个版本会更容易,因为0.9.6将在custom types中具有更大的灵活性。