La consola de Play2 no puede funcionar en postgresql
scala playframework (1)
Descubrí que los analizadores de fila de los modos de play2 dependen de los metadatos devueltos por el controlador jdbc.
Así que en la muestra incorporada "zentasks" proporcionada por play, puedo encontrar dicho código:
object Project {
val simple = {
get[Pk[Long]]("project.id") ~
get[String]("project.folder") ~
get[String]("project.name") map {
case id~folder~name => Project(id, folder, name)
}
}
}
Tenga en cuenta que todos los campos tienen un project.
prefijo.
Funciona bien en la base de datos h2, pero no en postgresql. Si uso portgresql, debería escribirlo como:
object Project {
val simple = {
get[Pk[Long]]("id") ~
get[String]("folder") ~
get[String]("name") map {
case id~folder~name => Project(id, folder, name)
}
}
}
He preguntado esto en el grupo de Google Play , y Guillaume Bort dijo:
Sí, si estás usando postgres es probablemente la causa. El controlador jdbc de postgresql está dañado y no devuelve nombres de tablas.
Si el controlador jdbc de postgresql realmente tiene este problema, creo que habrá un problema para anorm: si dos tablas tienen campos con el mismo nombre y les pregunto con join
, anorm no obtendrá los valores correctos , ya que puede '' t averiguar qué nombre pertenece a qué tabla.
Así que escribo una prueba.
1. crear tablas en postgresql
create table a (
id text not null primary key,
name text not null
);
create table b (
id text not null primary key,
name text not null,
a_id text,
foreign key(a_id) references a(id) on delete cascade
);
2. crear modelos anorm
case class A(id: Pk[String] = NotAssigned, name: String)
case class B(id: Pk[String] = NotAssigned, name: String, aId: String)
object A {
val simple = {
get[Pk[String]]("id") ~
get[String]("name") map {
case id ~ name =>
A(id, name)
}
}
def create(a: A): A = {
DB.withConnection { implicit connection =>
val id = newId()
SQL("""
insert into a (id, name)
values (
{id}, {name}
)
""").on(''id -> id, ''name -> a.name).executeUpdate()
a.copy(id = Id(id))
}
}
def findAll(): Seq[(A, B)] = {
DB.withConnection { implicit conn =>
SQL("""
select a.*, b.* from a as a left join b as b on a.id=b.a_id
""").as(A.simple ~ B.simple map {
case a ~ b => a -> b
} *)
}
}
}
object B {
val simple = {
get[Pk[String]]("id") ~
get[String]("name") ~
get[String]("a_id") map {
case id ~ name ~ aId =>
B(id, name, aId)
}
}
def create(b: B): B = {
DB.withConnection { implicit conneciton =>
val id = UUID.randomUUID().toString
SQL("""
insert into b (id, name, a_id)
values (
{id}, {name}, {aId}
)
""").on(''id -> id, ''name -> b.name, ''aId -> b.aId).executeUpdate()
b.copy(id = Id(id))
}
}
}
3. Casos de prueba con scalatest.
class ABTest extends DbSuite {
"AB" should "get one-to-many" in {
running(fakeApp) {
val a = A.create(A(name = "AAA"))
val b1 = B.create(B(name = "BBB1", aId = a.id.get))
val b2 = B.create(B(name = "BBB2", aId = a.id.get))
val ab = A.findAll()
ab foreach {
case (a, b) => {
println("a: " + a)
println("b: " + b)
}
}
}
}
}
4. la salida
a: A(dbc52793-0f6f-4910-a954-940e508aab26,BBB1)
b: B(dbc52793-0f6f-4910-a954-940e508aab26,BBB1,4a66ebe7-536e-4bd5-b1bd-08f022650f1f)
a: A(d1bc8520-b4d1-40f1-af92-52b3bfe50e9f,BBB2)
b: B(d1bc8520-b4d1-40f1-af92-52b3bfe50e9f,BBB2,4a66ebe7-536e-4bd5-b1bd-08f022650f1f)
Puede ver que las "a" tienen el nombre de "BBB1 / BBB2", pero no "AAA".
Intenté redefinir los analizadores con prefijos como:
val simple = {
get[Pk[String]]("a.id") ~
get[String]("a.name") map {
case id ~ name =>
A(id, name)
}
}
Pero informará errores que no pueden encontrar campos especificados.
¿Es un gran problema de anorm? ¿O me pierdo algo?
La última versión de play2 (RC3) resolvió este problema al verificar el nombre de clase del metaobjeto:
// HACK FOR POSTGRES
if (meta.getClass.getName.startsWith("org.postgresql.")) {
meta.asInstanceOf[{ def getBaseTableName(i: Int): String }].getBaseTableName(i)
} else {
meta.getTableName(i)
}
Pero tenga cuidado si quiere usarlo con p6spy
, no funciona porque el nombre de clase de meta será "com.p6spy ....", no "org.postgresql ....".