Гладко сопоставленные таблицы с использованием признаков выдают исключение

Я застрял, пытаясь определить сопоставленные таблицы, используя черты в slick 3.1.0. Поскольку в официальных документах ничего не упоминается, я даже не уверен, возможно это или нет. Вот что у меня есть на данный момент:

Определение таблицы:

class PersonTable(tag: Tag) extends Table[PersonModel](tag, "person") {
  def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
  def firstName = column[String]("first_name", O.Length(PersonDb.FirstNameColumnLength))
  def lastName = column[String]("last_name", O.Length(PersonDb.LastNameColumnLength))

  def * = (id.?, firstName, lastName) <> (PersonModelImpl.tupled, PersonModelImpl.unapply _)
}

PersonModel:

trait PersonModel {
  def id: Option[Int]
  def firstName: String
  def lastName: String
}

PersonModelImpl:

case class PersonModelImpl(
    override val id: Option[Int],
    override val firstName: String,
    override val lastName: String)
  extends PersonModel

Компиляция приведенного выше кода вызывает ошибку:

Compilation error[type mismatch;
  found   : slick.lifted.MappedProjection[models.PersonModelImpl,(Option[Int], String, String]
  required: slick.lifted.ProvenShape[models.PersonModel]]

Однако изменение ...extends Table[PersonModel]... на ...extends Table[PersonModelImpl]... в определении таблицы работает безупречно.

Итак, в основном мой вопрос:

  1. Можно ли использовать черты TableElementType в сопоставленных таблицах?
  2. Если да, что я делаю не так?

person Roman    schedule 03.12.2015    source источник


Ответы (1)


Ответы:

  1. Да, но для этого требуется правильная функция проецирования (*).
  2. У вас неправильный тип на *. Чтобы неявное разрешилось вправо MappedProjection, типы должны точно совпадать.

Вы сможете решить и то, и другое, выполнив:

def * = {
  val applyAsPersonModel: (Option[Int], String, String) => PersonModel =
    (PersonModelImpl.apply _)
  val unapplyAsPersonModel: PersonModel => Option[(Option[Int], String, String)] =
    { 
      // TODO: Handle any other subclasses of PersonModel you expect.
      case personImpl: PersonModelImpl => PersonModelImpl.unapply(personImpl)
    }
  (id.?, firstName, lastName) <> (applyAsPersonModel.tupled, unapplyAsPersonModel)
}

Обратите внимание на TODO. Вы получите исключение, если попытаетесь вставить какие-либо экземпляры, отличные от PersonModelImpl, если вы не добавите дополнительные операторы case к этой частичной функции. В качестве альтернативы вы можете просто создать новый экземпляр PersonModelImpl для перехода к unapply:

val unapplyAsPersonModel: PersonModel => Option[(Option[Int], String, String)] =
  { person: PersonModel =>             
    PersonModelImpl.unapply(
      PersonModelImpl(person.id, person.firstName, person.lastName)
    )
  }
person jkinkead    schedule 06.05.2016