【问题标题】:How to use ScalaQuery to insert a BLOB field?如何使用 ScalaQuery 插入 BLOB 字段?
【发布时间】:2010-10-22 02:18:11
【问题描述】:

我使用了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)使用的方法,BLOB类型字段如何操作(UPDATE, INSERT, SELECT)?

顺便说一句:没有 ScalaQuery 标签

【问题讨论】:

  • 感谢@Craig 帮助修复语法错误,我的英文不好,再次感谢。

标签: sql scala scalaquery


【解决方案1】:

由于 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 处理。阅读很直接:您只需在结果中得到一个由 JDBC 驱动程序实现的 Blob 对象,例如:

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

如果要插入或更新数据,则需要创建自己的 BLOB。 JDBC 的 RowSet 特性为独立的 Blob 对象提供了一个合适的实现:

import javax.sql.rowset.serial.SerialBlob

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

编辑:这是 Postgres 的 TypeMapper[Array[Byte]](ScalaQuery 尚不支持其 BLOB):

  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")
  }

【讨论】:

  • 我使用了上面的代码,但是 postgresql 驱动程序抛出了一个异常:在 org.postgresql.jdbc2.AbstractJdbc2ResultSet.getLong(AbstractJdbc2ResultSet. java:2032) 在 org.postgresql.jdbc3.Jdbc3ResultSet.getBlob(Jdbc3ResultSet.java:52) 在 org.scalaquery.session.PositionedResult.nextBlob(PositionedResult.scala:22),我看到了 postgresql JDBC 文档(jdbc.postgresql.org/documentation/83/binary-data.html) ,可能需要在 ResultSet 上使用 getBytes。
  • 确实,ScalaQuery 的标准 BLOB 处理还不能在 Postgres 上运行。 (该示例适用于 H2、MySQL、Derby 和 HsqlDb)。我已经为这个问题打开了github.com/szeiger/scala-query/issues/issue/7。目前,如果您需要给 DB 非标准类型名称或使用非标准访问器,您可以实现自己的 TypeMapper(可能用于比 java.sql.Blob 更方便使用的自定义类型)。
  • 抱歉,我尝试实现自己的 TypeMapper,我定义了新的 implicit object BArrayTypeMapper extends BaseTypeMapper[Array[Byte]]class BArrayTypeMapperDelegate extends TypeMapperDelegate[Array[Byte]],但是一个编译错误阻止了我,could not find implicit value for evidence parameter of type org.scalaquery.ql.TypeMapper[Option[Array[Byte]]]。你能给我一个在postgresql驱动程序上实现数组[字节]的示例代码吗,我的电子邮件sxpcrazy@gmail.com,非常感谢。
  • 我已经编辑了我的答案以包含一个 TypeMaper[Array[Byte]] 它适用于 Postgres 的 BYTEA 类型。
  • 我昨天定义了和你一样的代码,但是编译不出来,错误是could not find implicit value for evidence parameter of type org.scalaquery.ql.TypeMapper[Option[Array[Byte]]],我要导入一些隐式的辅助对象吗?
【解决方案2】:

我刚刚发布了 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)

【讨论】:

    猜你喜欢
    • 2011-02-19
    • 1970-01-01
    • 2011-09-20
    • 2012-02-22
    • 1970-01-01
    • 2012-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多