2010-10-22 3 views
6

Tôi đã sử dụng ScalaQuery và Scala.Làm thế nào để sử dụng ScalaQuery để chèn một trường BLOB?

Nếu tôi có đối tượng [Byte] mảng, làm thế nào để chèn nó vào bảng?

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) 

Tôi có thể xác định phương pháp được sử dụng def extInfo = column[Array[Byte]]("mbody", O.Nullable), cách vận hành (UPDATE, INSERT, SELECT) với trường loại BLOB không?

BTW: không có thẻ ScalaQuery

+0

cảm ơn @Craig giúp sửa lỗi ngữ pháp, tiếng anh của tôi không tốt, cảm ơn lần nữa. –

Trả lời

11

Kể từ khi lĩnh vực BLOB là nullable, tôi khuyên bạn nên thay đổi kiểu Scala của mình để lựa chọn [Blob], cho định nghĩa sau đây:

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

Bạn có thể sử dụng một liệu, giá trị Blob nullable nếu bạn thích, nhưng sau đó bạn cần phải sử dụng OrElse (null) trên cột để thực sự có được một giá trị null ra khỏi nó (thay vì ném một ngoại lệ):

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

Bây giờ cho một CTOB xử lý BLOB. Đọc sách là thẳng về phía trước: Bạn chỉ cần có được một đối tượng Blob trong kết quả đó được thực hiện bởi các trình điều khiển JDBC, ví dụ .:

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

Nếu bạn muốn chèn hoặc cập nhật dữ liệu, bạn cần phải tạo ra các đốm màu của riêng bạn. Một thực hiện thích hợp cho một đối tượng Blob độc lập được cung cấp bởi tính năng RowSet JDBC của:

import javax.sql.rowset.serial.SerialBlob 

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

Edit: Và đây là một TypeMapper [Array [Byte]] cho Postgres (có đốm màu chưa được hỗ trợ bởi 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

tôi đã sử dụng trên mã, nhưng postgresql driver ném một ngoại lệ: tại org.postgresql.jdbc2.AbstractJdbc2ResultSet.toLong (AbstractJdbc2ResultSet.java:2736) \t tại org.postgresql.jdbc2.AbstractJdbc2ResultSet.getLong (AbstractJdbc2ResultSet.java:2032) \t tại org.postgresql.jdbc3.Jdbc3ResultSet.getBlob (Jdbc3ResultSet.java:52) \t tại org.scalaquery.session.PositionedResult.nextBlob (PositionedResult.scala: 22), tôi thấy tài liệu JDBC postgresql (http: // jdbc .postgresql.org/documentation/83/binary-data.html), có thể cần sử dụng getBytes trên ResultSet. –

+0

Thật vậy, xử lý BLOB chuẩn của ScalaQuery không hoạt động trên Postgres. (Ví dụ làm việc cho tôi trên H2, MySQL, Derby và HsqlDb). Tôi đã mở http://github.com/szeiger/scala-query/issues/issue/7 cho vấn đề này. Bây giờ, nếu bạn cần cung cấp cho các tên loại không theo tiêu chuẩn DB hoặc sử dụng các trình truy cập không chuẩn, bạn có thể triển khai TypeMapper của riêng bạn (có thể cho một kiểu tùy chỉnh thuận tiện hơn cho bạn để sử dụng hơn java.sql.Blob). – szeiger

+1

Xin lỗi, tôi cố gắng tự thực hiện TypeMapper, tôi đã định nghĩa đối tượng ẩn mới 'BArrayTypeMapper mở rộng BaseTypeMapper [Array [Byte]]' và 'lớp BArrayTypeMapperDelegate mở rộng TypeMapperDelegate [Array [Byte]]', nhưng một lỗi biên dịch chặn tôi, 'có thể không tìm thấy giá trị tiềm ẩn cho tham số bằng chứng của loại org.scalaquery.ql.TypeMapper [Tùy chọn [Array [Byte]]] '.Bạn có thể gửi cho tôi một mã mẫu để thực hiện một mảng [Byte] trên trình điều khiển postgresql, email của tôi [email protected], cảm ơn bạn rất nhiều. –

1

tôi chỉ gửi một mã cập nhật cho Scala và SQ, có thể nó sẽ tiết kiệm thời gian cho ai đó:

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

} 

và sau đó sử dụng, ví dụ:

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