2010-10-22 17 views
6

Usé ScalaQuery y Scala.¿Cómo usar ScalaQuery para insertar un campo BLOB?

Si tengo un objeto Array [Byte], ¿cómo lo inserto en la tabla?

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) 

¿Puedo definir el método utilizado def extInfo = column[Array[Byte]]("mbody", O.Nullable), cómo operar (UPDATE, INSERT, SELECT) con el campo tipo BLOB?

Por cierto: ninguna etiqueta ScalaQuery

+0

gracias @Craig ayuda a corregir el error de gramática, mi inglés no es bueno, gracias de nuevo. –

Respuesta

11

Puesto que el campo BLOB es anulable, sugiero cambiando su tipo Scala a la opción [Blob], por la siguiente definición:

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

Se puede utilizar una prima, Blob valor anulable si lo prefiere, pero entonces es necesario utilizar orElse (nulo) en la columna para hacer que un valor nulo fuera de él (en lugar de lanzar una excepción):

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

Ahora para la una manejo de BLOB ctual. La lectura es directa: Usted acaba de obtener un objeto Blob en el resultado que se realiza mediante el controlador JDBC, por ejemplo .:

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

Si desea insertar o actualizar datos, tiene que crear sus propios BLOB. Una aplicación adecuada para un objeto Blob independiente es proporcionada por función RowSet de JDBC:

import javax.sql.rowset.serial.SerialBlob 

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

Editar: Y aquí hay una TypeMapper [Matriz [Byte]] para Postgres (cuyo BLOB sin embargo, no son compatibles con 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

utilicé anteriormente código, pero PostgreSQL controlador de lanzar una excepción: en org.postgresql.jdbc2.AbstractJdbc2ResultSet.toLong (AbstractJdbc2ResultSet.java:2736) \t en org.postgresql.jdbc2.AbstractJdbc2ResultSet.getLong (AbstractJdbc2ResultSet.java:2032) \t en org.postgresql.jdbc3.Jdbc3ResultSet.getBlob (Jdbc3ResultSet.java:52) \t en org.scalaquery.session.PositionedResult.nextBlob (PositionedResult.scala: 22), I ver las docs PostgreSQL JDBC (http: // jdbc .postgresql.org/documentation/83/binary-data.html), quizás necesite usar getBytes en el ResultSet. –

+0

De hecho, el manejo BLOB estándar de ScalaQuery aún no funciona en Postgres. (El ejemplo funciona para mí en H2, MySQL, Derby y HsqlDb). He abierto http://github.com/szeiger/scala-query/issues/issue/7 para este problema. Por ahora, si necesita dar nombres de tipos de DB no estándar o utilizar accesadores no estándar, puede implementar su propio TypeMapper (posiblemente para un tipo personalizado que le resulte más conveniente que java.sql.Blob). – szeiger

+1

Lo siento, trato de implementarme TypeMapper, definí el nuevo 'objeto implícito BArrayTypeMapper extiende BaseTypeMapper [Array [Byte]]' y 'clase BArrayTypeMapperDelegate extiende TypeMapperDelegate [Array [Byte]]', pero un error de compilación me bloquea, 'podría no se encuentra el valor implícito para el parámetro de evidencia del tipo org.scalaquery.ql.TypeMapper [Option [Array [Byte]]] '.¿Puede enviarme un código de muestra para implementar una matriz [Byte] en el controlador postgresql, mi correo electrónico [email protected], muchas gracias? –

1

acabo de publicar un código actualizado para la Scala y SQ, tal vez va a ahorrar algo de tiempo para alguien:

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

} 

y después del uso, por ejemplo:

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