2014-06-12 4 views
2

이것은 another question에서 파생 된 문제입니다. 왼쪽 된 조인이있는 Slick 쿼리에서 정렬 할 열을 동적으로 전달할 수 있어야합니다. 이 특정 상황에서의 문제는 왼쪽에 조인 된 테이블이 선택 사항이되어 그 문제를 처리하는 방법을 알지 못합니다. 나는 한 경우 테이블 Company 내가 갖는되지 않는 옵션의 SlickException: Read NULL value for ResultSet column PathSlick : 왼쪽 조인 쿼리에서 동적 sortBy

: 위의 예에서 사용 된

def list(filter: String, orderBy: Int) = { 

    DB.withDynSession { 

     val data = for { 
      (computer, company) <- Computer.where(_.name like filter) leftJoin 
       Company on (_.companyId === _.id) 
     } yield (computer, company.?) 

     val sortedData = orderBy match { 
      case 2 => data.sortBy(_._1.name) //Works ok, column from a primary table 
      case 3 => data.sortBy(_._2.name) //Error "Cannot resolve symbol name", because table is optional 
     } 

    } 

} 

슬릭 자동 생성 된 테이블 클래스 :

package tables 
// AUTO-GENERATED Slick data model 
/** Stand-alone Slick data model for immediate use */ 
object Tables extends { 
    val profile = scala.slick.driver.H2Driver 
} with Tables 

/** Slick data model trait for extension, choice of backend or usage in the cake pattern. (Make sure to initialize this late.) */ 
trait Tables { 
    val profile: scala.slick.driver.JdbcProfile 
    import profile.simple._ 
    import scala.slick.model.ForeignKeyAction 
    // NOTE: GetResult mappers for plain SQL are only generated for tables where Slick knows how to map the types of all columns. 
    import scala.slick.jdbc.{GetResult => GR} 

    /** DDL for all tables. Call .create to execute. */ 
    lazy val ddl = Company.ddl ++ Computer.ddl 

    /** Entity class storing rows of table Company 
    * @param id Database column ID PrimaryKey 
    * @param name Database column NAME */ 
    case class CompanyRow(id: Long, name: String) 
    /** GetResult implicit for fetching CompanyRow objects using plain SQL queries */ 
    implicit def GetResultCompanyRow(implicit e0: GR[Long], e1: GR[String]): GR[CompanyRow] = GR{ 
    prs => import prs._ 
    CompanyRow.tupled((<<[Long], <<[String])) 
    } 
    /** Table description of table COMPANY. Objects of this class serve as prototypes for rows in queries. */ 
    class Company(tag: Tag) extends Table[CompanyRow](tag, "COMPANY") { 
    def * = (id, name) <> (CompanyRow.tupled, CompanyRow.unapply) 
    /** Maps whole row to an option. Useful for outer joins. */ 
    def ? = (id.?, name.?).shaped.<>({r=>import r._; _1.map(_=> CompanyRow.tupled((_1.get, _2.get)))}, (_:Any) => throw new Exception("Inserting into ? projection not supported.")) 

    /** Database column ID PrimaryKey */ 
    val id: Column[Long] = column[Long]("ID", O.PrimaryKey) 
    /** Database column NAME */ 
    val name: Column[String] = column[String]("NAME") 
    } 
    /** Collection-like TableQuery object for table Company */ 
    lazy val Company = new TableQuery(tag => new Company(tag)) 

    /** Entity class storing rows of table Computer 
    * @param id Database column ID PrimaryKey 
    * @param name Database column NAME 
    * @param introduced Database column INTRODUCED 
    * @param discontinued Database column DISCONTINUED 
    * @param companyId Database column COMPANY_ID */ 
    case class ComputerRow(id: Long, name: String, introduced: Option[java.sql.Timestamp], discontinued: Option[java.sql.Timestamp], companyId: Option[Long]) 
    /** GetResult implicit for fetching ComputerRow objects using plain SQL queries */ 
    implicit def GetResultComputerRow(implicit e0: GR[Long], e1: GR[String], e2: GR[Option[java.sql.Timestamp]], e3: GR[Option[Long]]): GR[ComputerRow] = GR{ 
    prs => import prs._ 
    ComputerRow.tupled((<<[Long], <<[String], <<?[java.sql.Timestamp], <<?[java.sql.Timestamp], <<?[Long])) 
    } 
    /** Table description of table COMPUTER. Objects of this class serve as prototypes for rows in queries. */ 
    class Computer(tag: Tag) extends Table[ComputerRow](tag, "COMPUTER") { 
    def * = (id, name, introduced, discontinued, companyId) <> (ComputerRow.tupled, ComputerRow.unapply) 
    /** Maps whole row to an option. Useful for outer joins. */ 
    def ? = (id.?, name.?, introduced, discontinued, companyId).shaped.<>({r=>import r._; _1.map(_=> ComputerRow.tupled((_1.get, _2.get, _3, _4, _5)))}, (_:Any) => throw new Exception("Inserting into ? projection not supported.")) 

    /** Database column ID PrimaryKey */ 
    val id: Column[Long] = column[Long]("ID", O.PrimaryKey) 
    /** Database column NAME */ 
    val name: Column[String] = column[String]("NAME") 
    /** Database column INTRODUCED */ 
    val introduced: Column[Option[java.sql.Timestamp]] = column[Option[java.sql.Timestamp]]("INTRODUCED") 
    /** Database column DISCONTINUED */ 
    val discontinued: Column[Option[java.sql.Timestamp]] = column[Option[java.sql.Timestamp]]("DISCONTINUED") 
    /** Database column COMPANY_ID */ 
    val companyId: Column[Option[Long]] = column[Option[Long]]("COMPANY_ID") 

    /** Foreign key referencing Company (database name FK_COMPUTER_COMPANY_1) */ 
    lazy val companyFk = foreignKey("FK_COMPUTER_COMPANY_1", companyId, Company)(r => r.id, onUpdate=ForeignKeyAction.Restrict, onDelete=ForeignKeyAction.Restrict) 
    } 
    /** Collection-like TableQuery object for table Computer */ 
    lazy val Computer = new TableQuery(tag => new Computer(tag)) 
} 

답변

8

.?는 당신을 방지 <>를 사용하여 구현됩니다 나중에 회원에게 액세스 할 수 있습니다. 따라서하기 전에 정렬을 적용해야합니다. .?

val data = for { 
     (computer, company) <- Computer.where(_.name like filter) leftJoin 
      Company on (_.companyId === _.id) 
    } yield (computer, company) // <- no .? 

    val sortedData = orderBy match { 
     case 2 => data.sortBy(_._1.name) //Works ok, column from a primary table 
     case 3 => data.sortBy(_._2.name) //Error "Cannot resolve symbol name", because table is optional 
    } 

    val optionalJoinData = sortedData.map{ 
     case (computer, company) => (computer, company.?) 
    } // <- do .? last