2013-12-23 1 views
0

나는 학교 개체의 스칼라 슬릭 테이블을하고 난 0-5 매개 변수는 필터 객체 SchoolFilter 포함에 따라 필터링 할 :Scala SQL (Slick 1.0.1) 쿼리를 변경 가능하지 않은 방식으로 수행하려면 어떻게해야합니까?

case class SchoolFilter(name: Option[String], 
         city: Option[String], 
         state: Option[String], 
         zip: Option[String], 
         district: Option[String]) 

None 값에서 모든 키를 필터링하지 않음 "을 의미합니다 "나는 School 객체 테이블과 사용자 입력을 기반으로하는 필터를 수행하는 AJAX 호출이있는 html 페이지가 있기 때문입니다. 모든 학교의 변경 가능한 목록을 만든 다음 정의 된 각 구성원 인 SchoolFilter에서 필터를 실행하여이 동작을 구현했습니다. 그러나이 방법은 데이터베이스에서 모든 레코드를 빨아 들이고 그 결과를 반환하기 전에 목록을 5 번 통과하는 것이 매우 효율적으로 보이지 않습니다.

이 목표를 달성하는 데 더 기능적 (또는 더 효율적인) 방법이 있습니까?

def findSchoolsByFilter(f: SchoolFilter = SchoolFilter(None, None, None, None, None), 
         n: Int = 5) 
         (implicit session: Session) = Try { 
    var s = collection.mutable.LinkedList(Query(Schools).list().toSeq: _*) 
    if (f.name.isDefined) 
    s = s.filter(_.name.toLowerCase.startsWith(f.name.get.toLowerCase)) 
    if (f.city.isDefined) 
    s = s.filter(_.city.toLowerCase.startsWith(f.city.get.toLowerCase)) 
    if (f.state.isDefined) 
    s = s.filter(_.state.toLowerCase.startsWith(f.state.get.toLowerCase)) 
    if (f.zip.isDefined) 
    s = s.filter(_.zip.toLowerCase.startsWith(f.zip.get.toLowerCase)) 
    if (f.district.isDefined) 
    s = s.filter(_.district.toLowerCase.startsWith(f.district.get.toLowerCase)) 
    List(s.toSeq: _*).take(n).sorted 
} 
+0

제 생각에'Seq [SchoolFilter => Option [String]]'이 줄었습니다. – rightfold

+0

중복 코드에 관해서는 변경 가능한 목록에 대해서는별로 신경 쓰지 않겠지 만. 고차 함수를 사용하십시오. – rightfold

답변

3

로컬 변경 가능 (함수 내에 포함되어 누출되지 않음)은 일반적으로 문제가되지 않습니다. 같은 일을 수정하는 코드의 여러 위치에 대해 추론해야 할 때, 변경 가능성은 점점 더 커집니다. 그러나 기능 스타일을 사용하여 코드의 가독성과 효율성을 향상시킬 수 있습니다. 필터를 완전히 게으른 쿼리 작성기로 수행 할 수 있습니다. 데이터베이스 라운드 트립이없고, 적절한 쿼리를 작성하기 만하면됩니다. 즉, 더 이상 사용자 세션에 필요한 세션이 없습니다.

def findSchoolsByFilter(f: SchoolFilter = SchoolFilter(None, None, None, None, None), 
         n: Int = 5) = { 
    /** Case insensitive option startsWith */ 
    def iStartsWith(a:Column[String], bOption:Option[String]) = bOption.map(b => a.toLowerCase startsWith b.toLowerCase) 

    Query(Schools).filter(s => 
    Seq(
     iStartsWith(s.name, f.name), 
     iStartsWith(s.city, f.city), 
     iStartsWith(s.state, f.state), 
     iStartsWith(s.zip, f.zip), 
     iStartsWith(s.district, f.district) 
    ).flatten.reduce(_ && _) // flatten removes Nones and unwrap the Somes XMAS-Style 
).take(n) 
} 

당신도 한 단계 더 나아가 학교를 findSchoolsByFilter에 대한 주장을, 그래서 당신은 게으르게 다른 필터이 필터를 결합 할 수 있습니다.

관련 문제