2016-05-17 20 views
2

私は、クエリパラメータから文字列名に基づいて並べ替えるsortByを自分のクエリに動的に含めることを試みています。 Slick 3では、これはかなり難しいことが分かっています。Slick 3を使用した動的sortBy

trait Model { 
    type ATable <: AbstractTable[_] 

    def tableQuery: TableQuery[ATable] 

    def sortMap: Map[String, Rep[_]] 

    private def sortKey[T](e: ATable, sort: (String, SortOrder)): ColumnOrdered[_] = sort match { 
     case (field, SortOrder.Asc) => ColumnOrdered(sortMap.getOrElse(field, throw new ClientException(s"Can't sort by $field")), Ordering(Ordering.Asc)) 
     case (field, SortOrder.Desc) => ColumnOrdered(sortMap.getOrElse(field, throw new ClientException(s"Can't sort by $field")), Ordering(Ordering.Desc)) 
    } 
    def all(sort: (String, SortOrder)) = tableQuery.sortBy(sortKey(_, sort)).result 
} 

object User extends Model { 
    type ATable = Tables.User 
    val tableQuery = Tables.User 

    val sortMap = Map("id" -> tableQuery.id) 
} 

しかしdb.run(User.all(("id", SortOrder.Asc))を実行すると、次のエラーがスローされます:現在、私のセットアップがある

slick.SlickException: No type for symbol name found in Vector[t2<@t3<UnassignedType>>] 

誰もがよりよい解決策を知っていますか私は間違って行くよどこ?

答えて

0

私はこれが(Map[String, Rep[_]]からMap[String, ATable => Rep[_]]に)暗黙の列タイプとテーブルタイプを含むように私のsortMapを変更することでした解決方法:

trait Model { 
    type ATable <: AbstractTable[_] 

    def tableQuery: TableQuery[ATable] 

    def sortMap: Map[String, ATable => Rep[_]] 

    private def sortKey(baseQ: Query[ATable, ATable#TableElementType, Seq], sort: (String, SortOrder)) = { 
     val rep = sortMap.getOrElse(sort._1, throw new ClientException(s"Can't sort by ${sort._1}")) 
     val orderedRep = sort._2 match { 
      case SortOrder.Asc => (t: ATable) => ColumnOrdered(rep(t), slick.ast.Ordering(slick.ast.Ordering.Asc)) 
      case SortOrder.Desc => (t: ATable) => ColumnOrdered(rep(t), slick.ast.Ordering(slick.ast.Ordering.Desc)) 
     } 
     q.sortBy(orderedRep) 
    } 

    def all(sort: (String, SortOrder)) = sortKey(tableQuery, sort).result 
} 

object User extends Model { 
    type ATable = Tables.User 
    val tableQuery = Tables.User 

    val sortMap = Map("id" -> { (t: ATable) => t.id }) 
} 

このソリューションの唯一の次善の側面は、もし新しい列ということですデータベースに追加された場合、手動でsortKeyに追加する必要があります。これらのマップをテーブルコード生成スクリプトに含めることを検討しています。

0

あなただけの世代に

val columns = Map("id" -> { (t: User) => t.id }) 

のようなものが含まれるので、同じようにそれを使用する必要があります。

class UserDAO{ 
//... 
baseQuery = filterContext.sort.foldLeft[Query[User, UserRow, Seq]](User) ((_, s) => UserColumnFilter.getSort(s,User.baseTableRow.columns)); 
//... 
} 

case class Sort(columnName:String,value: String) {} 

case class FilterContext(filters:List[Filter],page:Int,pageSize:Int,sort:List[Sort]) 
    object UserColumnSort extends ColumnSort[User,UserRow](User) 
    class ColumnSort[T<:Table[C],C](query:TableQuery[T]) 
    {  

     def getSort(s:Sort,columns:Map[String, T => Rep[_]]):Query[T, C, Seq] = { 
     val aux = columns.getOrElse(s.columnName, throw new Exception(s"Can't sort by ${s.columnName}")); 
      val orderedRep = s.value match { 
       case "asc" => (t: T) => ColumnOrdered(aux(t), slick.ast.Ordering(slick.ast.Ordering.Asc)) 
       case _ => (t: T) => ColumnOrdered(aux(t), slick.ast.Ordering(slick.ast.Ordering.Desc)) 
      } 
      return query.sortBy(orderedRep); 

     } 
    } 
関連する問題