2016-11-27 5 views
0

最新のSlick 3.1.1を使用して汎用DAOを実装する方法については、生産性を高めるためにさまざまな可能性を模索していますが、そのためには、Play Webアプリケーションのサービスレイヤーを基にしてTableQueryをベースにすると、 。ジェネリックDAO実装で特色にしたいメソッドの1つはfindByExampleであり、Criteria APIの助けを借りてJPAで可能です。私の場合は、Slick Code Generatorを使用してSQLスクリプトからモデルクラスを生成しています。Slick:一般的な例findByExampleで実装する方法

私は次のように動的 Scala. Get field names list from case classから取られた属性名を、アクセスできるようにする必要があり

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はケースクラスとして生成される行タイプであるため、有効なScala Productタイプです。

このコードの第1の問題は、たとえばコードを実行する代わりに、あまりにも効率が悪いことです。

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機能を使用している間、そのような可能性はありませんか?

答えて

0

後。

モデルエンティティタイプに対応する一般的なfilterメソッドが宣言され、実装されています。したがって、JPA findByExampleの有効な機能的な置き換えは私の見解です。

すなわち

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) 
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

関連する問題