2014-09-23 61 views
0

我试图使用Couchbase作为缓存层来访问使用Slick的关系数据库。我的代码与问题相关的框架如下:使用Couchbase作为Slick的缓存

class RdbTable[T <: Table[_]](implicit val bucket: CouchbaseBucket) { 
    type ElementType = T#TableElementType 
    private val table = TableQuery[T].baseTableRow 

    private def cacheAll(implicit session: Session) = 
    TableQuery[T].list foreach (elem => cache(elem)) 

    private def cache(elem: ElementType) = 
    table.primaryKeys foreach (pk => bucket.set[ElementType](key(pk, elem), elem)) 

    private def key(pk: PrimaryKey, elem: ElementType) = ??? 
    ....... 
} 

正如您所看到的,我想通过它的所有主键缓存每个元素。为此,我需要获取给定元素的该键的值。但是我没有看到计算主键值的明显方式(列值,如果是单列键;元组值,如果是多列)。

关于怎么做的任何建议?请注意,代码不能知道实际的表和它们的列是什么。它必须是完全一般的。

回答

1

我们正在做类似的事情,使用Redis作为缓存。我们的每个记录都只有一个主键,但在某些情况下,我们需要在缓存键中包含其他数据以避免模糊(例如,我们有一个ManyToMany记录,表示两个记录之间的关联;当我们返回一个ManyToMany记录我们将嵌入一个(但不是两个)关联记录,因此在缓存键中我们需要包含我们要返回的关联记录的类型)。

abstract trait Record { 
    val cacheKey: CacheKey 
} 

trait ManyToManyRecord extends Record { 
    override val cacheKey: ManyToManyCacheKey 
} 

class CacheKey(recordType: String, key: Int) { 
    def getKey: String = recordType + ":" + key.toString 
} 

class ManyToManyCacheKey(recordType: String, key: Int, assocType: String) extends CacheKey { 
    def getKey: String = recordType + ":" + key.toString + ":" + assocType 
} 

我们所有的表都使用一个名为“id”的整数主键,所以我们很容易找出“key”的值。如果您正在处理更复杂的模式,并且不想手动为所有记录/表类型写出“def key:String”(或其他)定义,那么您可以尝试使用Slick code generation来自动生成记录/ table classes /带有“def key”的对象直接从模式创建。然而,Slick代码生成(或任何其他代码生成工具)的学习曲线非常陡峭,所以如果这是您唯一使用的代码,那么您最好手动生成“def key”。 (我们使用代码生成工具生成了我们代码的20%到30%之间的某个地方,因此在学习如何使用该工具方面的初始投资已经付清)

+0

谢谢,Zim-Zam!是的,我想我可以混合使用声明的密钥(),并在每个具体表类中定义它 - 然后跳过一些环来调用它,因为T被定义为扩展表[_] 。不是最好的解决方案,但肯定可行。然而,我的直觉告诉我,这不应该是必要的。 PrimaryKey对象知道它由哪些列组成,并且T#TableElementType行知道它的值,所以应该可以将它投影到主键列上。有多奇怪,似乎没有简单的程序化方式来做到这一点!或者在那里? – silverberry 2014-09-24 14:14:47

0

油滑不带有内置主键提取器为实体。你可以做的是使用接口,类型类或反射。例如。变种如下:

要么让你的实体实施特质

trait HasPrimaryKey{ 
    def primaryKey: Any 
} 
class RdbTable[T <: Table[_ <: HasPrimaryKey]](implicit val bucket: CouchbaseBucket) { 
    ... 
    private def key(elem: ElementType) = elem.primaryKey 

// and for each entity: 
case class Person(...) extends HasPrimaryKey{ 
    def primaryKey = ... 
} 

或类型类

trait KeyTypeClass[E,T <: Table[E]]{ 
    def key(e: E): Any 
} 
class RdbTable[T <: Table[_]](implicit val bucket: CouchbaseBucket, keyTC: KeyTypeClass[T]) { 
    ... 
    private def key(elem: ElementType) = keyTC(elem) 

// and for each entity: 
implicit val personKey = new KeyTypeClass[Person,PersonTable]{ 
    def key(p: Person) = ... 
} 

或使用反射来遍历主键和拉动值超出相应的实体的字段。

Zim-Zam提到的代码生成可以帮助重复元素。

+0

谢谢,cvogt!可惜Slick中没有主键提取器。在您的建议中,我更喜欢第二个,因为我不想用变通办法代码污染域模型类。 – silverberry 2014-09-24 14:35:58

+0

更多问题:如何通过此键(E)函数的值过滤查询?当我打电话过滤器(...)在查询实例中,“_”是T类型的,而不是E. – silverberry 2014-09-26 22:12:43

+0

您需要为E和T分别定义函数,所以如果您需要两者,则需要定义两次。 – cvogt 2014-09-28 14:02:21