2010-10-22 52 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)