【问题标题】:In Scala/Slick, how to refactor codes (respond interception) like this?在 Scala/Slick 中,如何像这样重构代码(响应拦截)?
【发布时间】:2015-03-03 09:51:46
【问题描述】:

代码如下:

def find(loginInfo: LoginInfo): Future[Option[UserProfile]] = {
  val res = DB.withSession { implicit session =>
    //if loginInfo.providerID == "waylens"
    userProfileTable.filter(u => u.userName === loginInfo.providerKey).list
  }
  val size = res.size
  if (size <= 1)
    Future(res.headOption.map(userProfileRecordToUserProfile))
  else
    throw new Exception("db error")
}

def findByEmail(providerID: String, email: String): Future[Option[UserProfile]] = {
  val res = DB.withSession { implicit session =>
    //if loginInfo.providerID == "waylens"
    userProfileTable.filter(u => u.email === email && u.status === 1).list
  }
  val size = res.size
  if (size <= 1)
    Future(res.headOption.map(userProfileRecordToUserProfile))
  else
    throw new Exception("db error")
}

def findByProfileID(profileID: Long): Future[Option[UserProfile]] = {
  val res = DB.withSession { implicit session =>
    userProfileTable.filter(u => u.id === profileID).list
  }
  val size = res.size
  if (size <= 1)
    Future(res.headOption.map(userProfileRecordToUserProfile))
  else
    throw new Exception("db error")
}

这些代码出现了很多次,真烦人

   val size = res.size
      if (size <= 1)
        Future(res.headOption.map(userProfileRecordToUserProfile))
      else
        throw new Exception("db error")

有人对在 Slick 中重构这个有想法吗?

【问题讨论】:

    标签: scala playframework slick slick-2.0 play-slick


    【解决方案1】:

    您可以在这里很容易地使用高阶函数,首先让我们从方法中取出您的查询:

    lazy val a = userProfileTable.filter(u => u.userName === loginInfo.providerKey)
    lazy val b = userProfileTable.filter(u => u.email === email && u.status === 1)
    lazy val c = userProfileTable.filter(u => u.id === profileID)
    

    请注意,我之所以懒惰是因为您还没有范围内的会话。

    现在让我们创建一个函数来执行此查询(您可以使用类型参数使其更加通用):

    def executeQuery(q: ⇒ : Query[UserProfiles, UserProfiles#TableElementType]): Int = {
      db.withSession { implicit session ⇒
        q.list
      }
    }
    

    然后我们需要检查长度:

    def listToUserProfile(list: List[UserProfile]): Future[Option[UserProfile]] = {
      if (list.length <= 1)
        Future(list.headOption.map(userProfileRecordToUserProfile))
      else
         throw new Exception("db error")
    }
    

    现在您可以执行以下操作:

    listToUserProfile(executeQuery(a))
    

    可能有一些错误,因为您的代码不可运行,我无法编译它。

    【讨论】:

    • .list 需要隐式会话。从 val a、b 和 c 中删除 .list 并将 .list 移动到 executeQuery 块中
    • 懒惰的巧妙运用。
    【解决方案2】:

    首先使用Either创建一个通用方法来执行返回未来或错误的查询

    
    def getElement[E, U, C[_]](query: Query[E, U, C]) = {
        db.withSession { implicit session =>
            query.list.headOption match {
                 case Some(ele) => Right(Future(ele))
                 case None => Left(new Exception("db error"))
           }
        }
      }
    

    现在在代码中,你可以简单地做

    
    def find(loginInfo: LoginInfo): Future[Option[UserProfile]] = 
          getElement(userProfileTable.filter(u => u.userName === loginInfo.providerKey)).right.map(userProfileRecordToUserProfile)
    

    对其他人也是如此:

    
    def findByEmail(loginInfo: LoginInfo): Future[Option[UserProfile]] = 
          getElement( userProfileTable.filter(u => u.email === email && u.status === 1))).right.map(userProfileRecordToUserProfile)
    

    附带说明,您没有将future 包装在 DB 调用上,而是在您获得结果之后。数据库调用将是阻塞的主要来源,而不是数据库结果的处理。您应该考虑在未来包装 DB 调用

    【讨论】:

      猜你喜欢
      • 2015-06-18
      • 1970-01-01
      • 1970-01-01
      • 2022-07-12
      • 1970-01-01
      • 2015-10-28
      • 1970-01-01
      • 2011-05-12
      • 1970-01-01
      相关资源
      最近更新 更多