2010-10-22 13 views
6

Ho usato ScalaQuery e Scala.Come utilizzare ScalaQuery per inserire un campo BLOB?

Se si dispone di un oggetto [Byte] array, come si inserisce nella tabella?

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) 

posso definire il metodo utilizzato def extInfo = column[Array[Byte]]("mbody", O.Nullable), come operare (UPDATE, INSERT, SELECT) con il campo di tipo BLOB?

BTW: nessun tag ScalaQuery

+0

grazie @ Craig aiutare correggere l'errore grammaticale, il mio inglese non è buono, grazie ancora. –

risposta

11

Dal momento che il campo BLOB è annullabile, suggerisco cambiando il suo tipo Scala di opzione [Blob], per la seguente definizione:

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]) 

è possibile utilizzare un grezzo, valore Blob nullable, se si preferisce, ma poi è necessario utilizzare orElse (null) sulla colonna per ottenere effettivamente un valore nullo fuori di esso (invece di lanciare un'eccezione):

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

Ora per l'una gestione del BLOC ctual. La lettura è straight-forward: Si ottiene solo un oggetto Blob nel risultato che viene realizzato tramite il driver JDBC, ad es .:

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

Se si desidera inserire o aggiornare i dati, è necessario creare i propri BLOB. Un'implementazione adatto per un oggetto Blob stand-alone è fornita da funzionalità RowSet di JDBC:

import javax.sql.rowset.serial.SerialBlob 

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

Edit: Ed ecco un TypeMapper [Array [Byte]] per Postgres (i cui i BLOB non sono ancora supportati da 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

Ho usato sopra il codice, ma PostgreSQL driver un'eccezione: a org.postgresql.jdbc2.AbstractJdbc2ResultSet.toLong (AbstractJdbc2ResultSet.java:2736) \t a org.postgresql.jdbc2.AbstractJdbc2ResultSet.getLong (AbstractJdbc2ResultSet.java:2032) \t a org.postgresql.jdbc3.Jdbc3ResultSet.getBlob (Jdbc3ResultSet.java:52) \t a org.scalaquery.session.PositionedResult.nextBlob (PositionedResult.scala: 22), vedo la documentazione PostgreSQL JDBC (http: // JDBC .postgresql.org/documentation/83/binary-data.html), forse è necessario utilizzare getBytes sul ResultSet. –

+0

Infatti, la gestione BLOB standard di ScalaQuery non funziona ancora su Postgres. (L'esempio funziona per me su H2, MySQL, Derby e HsqlDb). Ho aperto http://github.com/szeiger/scala-query/issues/issue/7 per questo problema. Per ora, se è necessario fornire nomi di tipi non standard di DB o utilizzare accessor non standard, è possibile implementare il proprio TypeMapper (possibilmente per un tipo personalizzato che è più conveniente da utilizzare rispetto a java.sql.Blob). – szeiger

+1

dispiace, cerco di implementare me TypeMapper, ho definito il nuovo 'oggetto implicita BArrayTypeMapper estende BaseTypeMapper [Array [Byte]]' e 'classe BArrayTypeMapperDelegate estende TypeMapperDelegate [Array [Byte]]', ma un errore di compilazione mi bloccano, 'potrebbe non trovare il valore implicito per parametro evidence di tipo org.scalaquery.ql.TypeMapper [Option [Array [Byte]]].Potete inviarmi un codice di esempio per implementare un array [Byte] sul driver postgresql, la mia email [email protected], grazie mille. –

1

ho appena inviare un codice aggiornato per Scala e SQ, forse sarà risparmiare un po 'di tempo per qualcuno:

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

} 

e poi l'utilizzo, ad esempio:

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