我有一个带有多个表的MySQL 5.7数据库,这些表将UUID存储在具有VARCHAR数据类型的列中。我试图将我们的代码库转换为使用Slick 3.1.1,但我遇到了UUID到String转换的问题。这是我的专栏定义:
def myCol: Rep[UUID] = column[UUID]("myCol", SqlType("VARCHAR"))
当我运行查询时,我得到这样的例外:
Got the exception java.sql.SQLException: Incorrect string value: '\xDA\xFD\xDAuOL...' for column 'myCol' at row 1
根据我的理解,Slick假设UUID应该存储为二进制列类型,所以我尝试使用以下方法隐式转换为String:
implicit val uuidToString = MappedColumnType.base[UUID, String](_.toString, UUID.fromString)
def myCol: Rep[UUID] = column[UUID]("myCol", SqlType("VARCHAR"))(uuidToString)
这适用于插入,但当我选择带有myCol
的值时,结果将为空。任何人都知道如何强制Slick使用VARCHAR而不是BINARY(16)进行数据转换?
编辑:
隐式此查询不会返回任何结果:
db.run { table.filter(_.myCol === val)).result }
但是这个确实:
db.run { table.result }.map(_.filter(_.myCol == val))
EDIT2:
我在这里有一个带有演示的小项目:https://github.com/nmatpt/slick-uuid-test
答案 0 :(得分:6)
您确定来自db的空值吗?我刚检查了我的实现(在其中一个项目中,完全相同的解决方案),它似乎完美无缺。确保您的物理列(在DB中)实际上是VARCHAR类型(而不是某些二进制文件)。
编辑:
好的,我们遇到的问题是UUID
定义为BINARY
已包含在MySQL配置文件中。快速(虽然可能有点脏)是全局重新定义它会是这样的:
package profile
import java.sql.{PreparedStatement, ResultSet}
import slick.ast._
import slick.jdbc.MySQLProfile
object CustomMySqlProfile extends MySQLProfile {
import java.util.UUID
override val columnTypes = new JdbcTypes
class JdbcTypes extends super.JdbcTypes {
override val uuidJdbcType = new UUIDJdbcType {
override def sqlTypeName(sym: Option[FieldSymbol]) = "UUID"
override def valueToSQLLiteral(value: UUID) = "'" + value + "'"
override def hasLiteralForm = true
override def setValue(v: UUID, p: PreparedStatement, idx: Int) = p.setString(idx, toString(v))
override def getValue(r: ResultSet, idx: Int) = fromString(r.getString(idx))
override def updateValue(v: UUID, r: ResultSet, idx: Int) = r.updateString(idx, toString(v))
private def toString(uuid: UUID) = if(uuid != null) uuid.toString else null
private def fromString(uuidString: String) = if(uuidString != null) UUID.fromString(uuidString) else null
}
}
}
然后导入它而不是常规api
:
import profile.CustomMySqlProfile.api._
这肯定有效 - 但请记住,现在UUID将在整个应用程序中映射到字符串(而不是默认的二进制文件)。基本上我只需要覆盖配置文件,因为UUID
转换是内置的。通常你会使用类型映射。
类似的方法在这里以类似的方式解决了:https://github.com/slick/slick/issues/1446(也是UUID,但是对于Oracle驱动程序)。
答案 1 :(得分:1)
implicit val uuidToString = MappedColumnType.base[UUID, String](_.toString, UUID.fromString)
@QP,这对于选择也可以正常工作,但是在为包含“UUID”的VARCHAR列构造查询的任何地方,这个隐式转换都在范围内是必不可少的。否则,选择WHERE
条件将永远不会匹配并返回空结果。