无法创建定义通用行为的特征

时间:2018-04-17 10:11:37

标签: scala

以下trait定义了表示数据库的类应该实现的常用方法。它有一个方法getOneById,它接受​​id(比如对应表的主键)并返回一些值或Noneid可以是单个值(例如电子邮件ID)或多个值(例如桶ID和电子邮件ID),例如,bucket = 1和email =" mc@mc.com"。

abstract trait Repository[I,M] {    
    def getOneById(id: I): Option[M]
}

实施可能是(使用I以下我不知道要定义为I)。 Usercase class

class CassandraRepository[I ,User] (session: Session, tablename: String, partitionKeyColumns: List[String]) extends Repository [I,User] {
def getOneById(id:I): M = {

    /*eg. select * from users where bucket=1 and email='mc@mc.com';*/
    val selectStmt =
      select()
        .from(tablename)
        .where(QueryBuilder.eq(partitionKeyColumns(0), `some value from id should come here`)).and(QueryBuilder.eq(partitionKeyColumns(1), `if multiple ids, some other value of id should come here`)) 
        .limit(1)


    val resultSet = session.execute(selectStmt)
    val row = resultSet.one() //get 1st value only 
    row.toUser(); //assume a function which converts row data to User case class
  }

I应该是什么?我认为我将值表示为case class,但是我如何在此处传递case class,因为根据搜索的表,不同的类可能具有不同的字段。例如

  • User表可以bucketId:Intemail:String作为主键,在这种情况下,查询中的代码将为.where(QueryBuilder.eq(partitionKeyColumns(0), id.bucketId))).and(QueryBuilder.eq(partitionKeyColumns(1), id.email))
  • Product表可以bucketId:IntproductCode:Int作为主键,在这种情况下,查询中的代码将为.where(QueryBuilder.eq(partitionKeyColumns(0), id.bucketId))).and(QueryBuilder.eq(partitionKeyColumns(1), id.productCode))

我怎么能写出这样的通用特征?

2 个答案:

答案 0 :(得分:1)

同样,您正在混合类型和类型参数。如果您希望CassandraRepository也是通用的,那么您将拥有例如。

class CassandraRepository[I, M](...) extends Repository[I, M] {
  // calls conditions and fromRow 
  def getOneById(id: I): Option[M] = ...

  // abstract methods which will be implemented differently depending on I and M
  def conditions(id: I): List[Clause]
  def fromRow(row: Row): M 
}

case class UserKey(bucketId: Int, email: String)

object CassandraUserRepository extends CassandraRepository[UserKey, User](...) {
  // note that here you don't use I and M, but concrete types
  def conditions(id: UserKey) = List(
    QueryBuilder.eq("bucketId", id.bucketId), 
    QueryBuilder.eq("email", id.email)
  )
  def fromRow(row: Row): User = ...
}

您可以在Rich的答案中使用解决方案来避免抽象conditions

答案 1 :(得分:0)

我觉得你在这里陷入困境。也许退一步考虑是否花费大量精力编写一个参数化的Repository实际上比为不同的类具有不同的Repositories更好。

话虽如此,我认为在这里达到你想要的最简单的方法是将Id特性设为Product,然后使用zip和{{1}设置partitionKeyColumns使用fold制作“where”子句。