Как использовать ScalaQuery для вставки поля BLOB? - PullRequest
6 голосов
/ 22 октября 2010

Я использовал ScalaQuery и Scala.

Если у меня есть объект Array [Byte], как мне вставить его в таблицу?

object TestTable extends BasicTable[Test]("test") {
  def id = column[Long]("mid", O.NotNull)
  def extInfo = column[Blob]("mbody", O.Nullable)

  def * = id ~ extInfo <> (Test, Test.unapply _)
}

case class Test(id: Long, extInfo: Blob)

Можно ли определить используемый метод def extInfo = column[Array[Byte]]("mbody", O.Nullable), как работать (UPDATE, INSERT, SELECT) с полем типа BLOB?

Кстати: нет тега ScalaQuery

Ответы [ 2 ]

11 голосов
/ 22 октября 2010

Поскольку поле BLOB можно обнулять, я предлагаю изменить его тип Scala на Option [Blob] для следующего определения:

object TestTable extends Table[Test]("test") {
  def id = column[Long]("mid")
  def extInfo = column[Option[Blob]]("mbody")
  def * = id ~ extInfo <> (Test, Test.unapply _)
}

case class Test(id: Long, extInfo: Option[Blob])

Вы можете использовать необработанное значение Blob с нулевым значением, если хотите, но затем вам нужно использовать orElse (null) для столбца, чтобы фактически получить из него нулевое значение (вместо создания исключения):

      def * = id ~ extInfo.orElse(null) <> (Test, Test.unapply _)

Теперь для фактической обработки BLOB. Чтение просто: вы просто получаете объект Blob в результате, который реализуется драйвером JDBC, например ::1007*

  Query(TestTable) foreach { t =>
    println("mid=" + t.id + ", mbody = " +
      Option(t.extInfo).map { b => b.getBytes(1, b.length.toInt).mkString })
  }

Если вы хотите вставить или обновить данные, вам нужно создать свои собственные большие двоичные объекты. Подходящая реализация для отдельного объекта Blob обеспечивается функцией RowSet JDBC:

import javax.sql.rowset.serial.SerialBlob

TestTable insert Test(1, null)
TestTable insert Test(2, new SerialBlob(Array[Byte](1,2,3)))

Редактировать: А вот TypeMapper [Array [Byte]] для Postgres (чьи большие двоичные объекты еще не поддерживаются ScalaQuery):

  implicit object PostgresByteArrayTypeMapper extends
      BaseTypeMapper[Array[Byte]] with TypeMapperDelegate[Array[Byte]] {
    def apply(p: BasicProfile) = this
    val zero = new Array[Byte](0)
    val sqlType = java.sql.Types.BLOB
    override val sqlTypeName = "BYTEA"
    def setValue(v: Array[Byte], p: PositionedParameters) {
      p.pos += 1
      p.ps.setBytes(p.pos, v)
    }
    def setOption(v: Option[Array[Byte]], p: PositionedParameters) {
      p.pos += 1
      if(v eq None) p.ps.setBytes(p.pos, null) else p.ps.setBytes(p.pos, v.get)
    }
    def nextValue(r: PositionedResult) = {
      r.pos += 1
      r.rs.getBytes(r.pos)
    }
    def updateValue(v: Array[Byte], r: PositionedResult) {
      r.pos += 1
      r.rs.updateBytes(r.pos, v)
    }
    override def valueToSQLLiteral(value: Array[Byte]) =
      throw new SQueryException("Cannot convert BYTEA to literal")
  }
1 голос
/ 24 ноября 2011

Я просто выкладываю обновленный код для Scala и SQ, возможно, это сэкономит кому-то время:

object PostgresByteArrayTypeMapper extends
    BaseTypeMapper[Array[Byte]] with TypeMapperDelegate[Array[Byte]] {
  def apply(p: org.scalaquery.ql.basic.BasicProfile) = this
  val zero = new Array[Byte](0)
  val sqlType = java.sql.Types.BLOB
  override val sqlTypeName = "BYTEA"
  def setValue(v: Array[Byte], p: PositionedParameters) {
    p.pos += 1
    p.ps.setBytes(p.pos, v)
  }
  def setOption(v: Option[Array[Byte]], p: PositionedParameters) {
    p.pos += 1
    if(v eq None) p.ps.setBytes(p.pos, null) else p.ps.setBytes(p.pos, v.get)
  }
  def nextValue(r: PositionedResult) = {
    r.nextBytes()
  }
  def updateValue(v: Array[Byte], r: PositionedResult) {
    r.updateBytes(v)
  }
  override def valueToSQLLiteral(value: Array[Byte]) =
    throw new org.scalaquery.SQueryException("Cannot convert BYTEA to literal")

}

и затем использование, например:

...
// defining a column
def content = column[Array[Byte]]("page_Content")(PostgresByteArrayTypeMapper)
...