Как я могу фильтровать с помощью inSetBind несколько столбцов в Slick?

У меня есть следующее определение таблицы (упрощенное):

class Houses(tag: Tag) extends Table[HouseRow](tag, "HOUSE") {
  def houseId = column[Long]("HOUSE_ID", O.NotNull, O.PrimaryKey, O.AutoInc)
  def houseName = column[String]("HOUSE_NAME", O.NotNull)
  def houseType = column[String]("HOUSE_TYPE", O.NotNull)

  def uniqueHouseName = index("UQ_HOUSE_NAME_HOUSE_TYPE", (houseName, houseType), true)

  def * = (houseId, houseName, houseType) <> (HouseRow.tupled, HouseRow.unapply)
}

val houses = TableQuery[Houses]

Я хотел бы выбрать дома, которые соответствуют набору индекса uniqueHouseName, следующим образом.

case class HouseKey(houseName: String, houseType: String)
val houseKeys: Seq(HouseKey("name1", "type1"), HouseKey("name2", "type2"))

Наивный фильтр inSetBind будет соответствовать, например. HouseRow(ID, "name1", "type2") что неверно. В MySql я бы сделал что-то вроде:

SELECT * FROM HOUSE h
WHERE(h.HOUSE_TYPE, d.HOUSE_NAME) IN
(
  SELECT 'type1' as HOUSE_TYPE, 'name1' as HOUSE_NAME
  UNION
  SELECT 'type2', 'name2'
);

person Klugscheißer    schedule 31.10.2014    source источник


Ответы (3)


Адаптация ответа tuxdna для разрешения произвольных последовательностей. Однако в настоящее время этот запрос не может быть предварительно скомпилирован в SQL и имеет дополнительные затраты времени выполнения.

val filteredHouses =  
  houses.filter(h =>
    houseKeys.map(hk => h.houseName === hk.houseName && h.houseType === hk.houseType)
              .reduce(_ || _)
  )
person cvogt    schedule 03.11.2014
comment
Просто предупреждение, reduce взрывается в пустом списке. - person Klugscheißer; 04.11.2014

Как версия @cvogt, но не взрывается в пустом списке:

val filteredHouses = 
  houses.filter(h =>
    houseKeys.map(hk => h.houseName === hk.houseName &&
        h.houseType === hk.houseType)
      .reduceOption(_ || _).getOrElse(false: Rep[Boolean])
)

Протестировано в слике 3.1.0

person Cale    schedule 22.10.2015

Это не полный ответ, но вы можете сделать это только для двух пар значений:

   val filteredHouses =  for {
      h <- houses
      if (h.houseName === "name1" && h.houseType === "type1") || (
        h.houseName === "name2" && h.houseType === "type2")
    } yield h
person tuxdna    schedule 31.10.2014