2010-10-22 51 views
6

我用ScalaQuery和斯卡拉。如何使用ScalaQuery插入BLOB字段?

如果我有一个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类型字段?

BTW:没有ScalaQuery标签

+0

谢谢@Craig帮助修复了语法错误,我的英文不好,再次感谢。 – 2010-10-22 03:13:34

回答

11

由于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值,如果你喜欢,但你需要在列中使用否则容易(空)出它真正得到一个空值(而不是抛出异常的):

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

现在的一实际的BLOB处理。阅读是直接的:你只得到一个Blob对象,其中通过JDBC驱动程序实现的

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

如果你想插入或更新数据,您需要创建自己的BLOB的结果,例如:。

import javax.sql.rowset.serial.SerialBlob 

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

编辑:为一个独立的Blob对象的合适的实现是通过JDBC的行集功能提供,这里有一个TypeMapper [数组[字节] Postgres的(他们的BLOB尚未被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") 
    } 
+0

我上面的代码中使用,但PostgreSQL驱动抛出异常:在org.postgresql.jdbc2.AbstractJdbc2ResultSet.toLong(AbstractJdbc2ResultSet.java:2736) \t在org.postgresql.jdbc2.AbstractJdbc2ResultSet.getLong(AbstractJdbc2ResultSet.java:2032) \t at org.postgresql.jdbc3.Jdbc3ResultSet.getBlob(Jdbc3ResultSet.java:52) \t at org.scalaquery.session.PositionedResult.nextBlob(PositionedResult.scala:22),我看到了postgresql JDBC文档(http:// jdbc .postgresql.org/documentation/83/binary-data.html),可能需要在ResultSet上使用getBytes。 – 2010-10-23 06:19:24

+0

确实,ScalaQuery的标准BLOB处理在Postgres上还不能运行。 (这个例子适用于H2,MySQL,Derby和HsqlDb)。我为这个问题打开了http://github.com/szeiger/scala-query/issues/issue/7。现在,如果您需要为数据库提供非标准类型名称或使用非标准访问器,则可以实现自己的TypeMapper(可能用于比java.sql.Blob更方便使用的自定义类型)。 – szeiger 2010-10-24 21:40:38

+1

对不起,我尝试自己实现TypeMapper,我定义了新的'隐式对象BArrayTypeMapper extends BaseTypeMapper [Array [Byte]]'和'class BArrayTypeMapperDelegate extends TypeMapperDelegate [Array [Byte]]',但是有一个编译错误会阻止我''可以找不到类型为org.scalaquery.ql.TypeMapper [Option [Array [Byte]]]的证据参数的隐式值。你可以给我一个示例代码来实现一个数组[字节] postgresql驱动程序,我的电子邮件[email protected],非常感谢你。 – 2010-10-25 02:50:22

1

我刚刚发布一个更新的代码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)