0

我正在探索如何使用最新的Slick 3.1.1实现通用 DAO以提高生产力的不同可能性,是的,需要它,因为TableQuery单独基于我的 Play Web 应用程序的服务层会导致大量样板代码. 我想在我的通用 DAO 实现中使用的方法之一是findByExample, 在 JPA 中可能在Criteria API的帮助下。就我而言,我使用Slick Code Generator从 sql 脚本生成模型类。

我需要以下内容才能动态访问取自Scala 的属性名称。从案例类中获取字段名称列表

import scala.reflect.runtime.universe._

def classAccessors[T: TypeTag]: List[MethodSymbol] = typeOf[T].members.collect {
    case m: MethodSymbol if m.isCaseAccessor => m
}.toList 

实施草案findByExample将是:

def findByExample[T, R](example: R) : Future[Seq[R]] = {
  var qt = TableQuery[T].result
  val accessors = classAccessors[R]
  (0 until example.productArity).map { i =>
    example.productElement(i) match {
      case None => // ignore
      case 0 => // ignore
      // ... some more default values => // ignore  
      // handle a populated case   
      case Some(x) => {
        val columnName = accessors(i)
        qt = qt.filter(_.columnByName(columnName) == x)
      }
    }
  }
  qt.result
}

但这不起作用,因为我需要更好的 Scala Kungfu。T是实体表类型R,是作为案例类生成的行类型,因此是有效的 ScalaProduct类型。

该代码中的第一个问题是效率太低,因为不是做例如

qt.filter(_.firstName === "Juan" && _.streetName === "Rosedale Ave." && _.streetNumber === 5)

是在做:

// find all
var qt = TableQuery[T].result
// then filter by each column at the time
qt = qt.filter(_.firstName === "Juan")
qt = qt.filter(_.streetName === "Rosedale Ave.")
qt = qt.filter(_.streetNumber === 5)

其次,我看不到如何在过滤方法中动态访问列名,即

qt.filter(_.firstName == "Juan") 

我需要改为

qt.filter(_.columnByName("firstName") == "Juan")

但显然在使用该功能时没有这种可能性filter

4

2 回答 2

1

可能通过动态提供的列名实现过滤器和排序的最佳方法是纯 SQL 或扩展代码生成器以生成扩展方法,如下所示:

implicit class DynamicPersonQueries[C[_]](q: Query[PersonTable, PersonRow, C]){
  def dynamicFilter( column: String, value: String ) = column {
    case "firstName" => q.filter(_.firstName === value)
    case "streetNumber" => q.filter(_.streetNumber === value.toInt)
    ...
  }
}

您可能需要稍微摆弄一下类型才能编译它(最好在之后更新这篇文章:))。

然后,您可以按所有提供的值进行过滤,如下所示:

val examples: Map[String, String] = ...
val t = TableQuery[PersonTable]
val query = examples.foldLeft(t){case (t,(column, value)) => t.dynamicFilter(column, value)
query.result

此处解释了扩展代码生成器:http: //slick.lightbend.com/doc/3.1.1/code-generation.html#customization

于 2016-11-28T02:37:16.903 回答
0

经过进一步研究发现以下博客文章Repository Pattern / Generic DAO Implementation

他们在那里声明并实现了一个filter适用于任何模型实体类型的通用方法,因此在我看来,它是对更多 JPA 的有效功能替代findByExample

IE

T <: Table[E] with IdentifyableTable[PK]
E <: Entity[PK]
PK: BaseColumnType

def filter[C <: Rep[_]](expr: T => C)(implicit wt: CanBeQueryCondition[C]) : Query[T, E, Seq] = tableQuery.filter(expr)
于 2016-12-06T11:50:32.623 回答