Scala/Slick:如何查询表和return自定义对象序列
Scala/Slick: how to query tables and return sequence of custom objects
我对 scala 和 slick 还很陌生。我无法从此功能中获取联系人的顺序。每个联系人对象都有名字、姓氏和一系列 phone 数字。姓名和 phone 号码使用外键存储在各自的表中。
def testContacts: Future[Seq[Contact]] = {
names.result.map { namelist =>
var contacts = Seq[Contact]()
for (n <- namelist) {
println("NAME: " + n) // THIS IS PRINTED!
val phoneNumbers = for {
p <- phones.filter(_.nameId === n.id)
} yield p.phoneNumber
phoneNumbers.result.map { plist =>
contacts = contacts :+ Contact(n.firstName, n.lastName, plist)
// Q: HOW DO I RETURN "contacts" to the caller?
println("CONTACTS: " + plist) // THIS IS **NOT** PRINTED!
}
}
}
Future { Seq[Contact]() } // dummy statement to avoid compilation error
}
来自控制台:
scala> Await.result(db.run(names.result), 1000 毫秒)
res9: Seq[Example.NameTable#TableElementType] = Vector(Name(George,W,1), Name(John,A,2))
scala> Await.result(db.run(phones.result), 1000 毫秒)
res10: Seq[Example.PhoneTable#TableElementType] = Vector(Phone(+1 301 531 1121,1,1), Phone(+1 301 748 5192,1,2), Phone(+1 301 531 4519,2,3), Phone(+1 202 667 9612,2,4), Phone(+1 202 667 4044,2,5))
scala> Await.result(testContacts, 1000 毫秒)
res5: Seq[Contacts.Contact] = 列表()
scala>
感谢任何帮助。这是完整的源代码:
import scala.concurrent.Await
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
import slick.driver.H2Driver.api._
import scala.util.Try
import scala.concurrent.Future
object Contacts extends App {
val db = Database.forConfig("dbconfig")
case class Contact(firstName: String, lastName: String, phones: Seq[String])
def testContacts: Future[Seq[Contact]] = {
names.result.map { namelist =>
var contacts = Seq[Contact]()
for (n <- namelist) {
println("NAME: " + n)
val phoneNumbers = for {
p <- phones.filter(_.nameId === n.id)
} yield p.phoneNumber
phoneNumbers.result.map { plist =>
contacts = contacts :+ Contact(n.firstName, n.lastName, plist)
// Q: HOW DO I RETURN "contacts" to the caller?
println("CONTACTS: " + plist) // THIS IS NOT PRINTED!
}
}
}
Future { Seq[Contact]() } // dummy statement to avoid compilation error
}
case class Name(firstName: String, lastName: String, id: Long = 0L)
class NameTable(tag: Tag) extends Table[Name](tag, "Names") {
def id = column[Long]("ID", O.PrimaryKey, O.AutoInc)
def firstName = column[String]("FIRSTNAME")
def lastName = column[String]("LASTNAME")
override def * = (firstName, lastName, id) <> (Name.tupled, Name.unapply)
}
lazy val names = TableQuery[NameTable]
case class Phone(phoneNumber: String, nameId: Long, id: Long = 0L)
class PhoneTable(tag: Tag) extends Table[Phone](tag, "Phones") {
def id = column[Long]("ID", O.PrimaryKey, O.AutoInc)
def phoneNumber = column[String]("PHONE_NUMBER")
def nameId = column[Long]("NAME")
override def * = (phoneNumber, nameId, id) <> (Phone.tupled, Phone.unapply)
def name_fk = foreignKey("Phones_Names_ID_FK", nameId, names)(_.id, onUpdate = ForeignKeyAction.Cascade, onDelete = ForeignKeyAction.Cascade)
}
lazy val phones = TableQuery[PhoneTable]
def testNames = Seq(
Name("George", "W"),
Name("John", "A"))
def testPhones = Seq(
Phone("+1 301 531 1121", 1L),
Phone("+1 301 748 5192", 1L),
Phone("+1 301 531 4519", 2L),
Phone("+1 202 667 9612", 2L),
Phone("+1 202 667 4044", 2L))
def populate: DBIOAction[Option[Int], NoStream,Effect.All] = {
for {
_ <- names.schema.drop.asTry andThen names.schema.create
_ <- phones.schema.drop.asTry andThen phones.schema.create
nameCount <- names ++= testNames
phoneCount <- phones ++= testPhones
} yield nameCount
}
}
您的 testContacts 查询不是很直接,我会在查询语句中使用连接或过滤器,然后展开行
这是我会尝试的方法
def testContacts: Future[Seq[Contact]] = {
val query = for {
(n, pl) <- names join phones on (_.id === _.nameId)
} yield (n, pl)
db.run(query.result).map { (row) =>
row.groupBy(_._1).map { r =>
val name = r._1
val phones = r._2.map(_._2.phoneNumber)
Contact(name.firstName, name.lastName, phones)
}.toSeq
}
}
这使用巧妙的 forcomp
连接语法,然后映射结果
我对 scala 和 slick 还很陌生。我无法从此功能中获取联系人的顺序。每个联系人对象都有名字、姓氏和一系列 phone 数字。姓名和 phone 号码使用外键存储在各自的表中。
def testContacts: Future[Seq[Contact]] = {
names.result.map { namelist =>
var contacts = Seq[Contact]()
for (n <- namelist) {
println("NAME: " + n) // THIS IS PRINTED!
val phoneNumbers = for {
p <- phones.filter(_.nameId === n.id)
} yield p.phoneNumber
phoneNumbers.result.map { plist =>
contacts = contacts :+ Contact(n.firstName, n.lastName, plist)
// Q: HOW DO I RETURN "contacts" to the caller?
println("CONTACTS: " + plist) // THIS IS **NOT** PRINTED!
}
}
}
Future { Seq[Contact]() } // dummy statement to avoid compilation error
}
来自控制台:
scala> Await.result(db.run(names.result), 1000 毫秒) res9: Seq[Example.NameTable#TableElementType] = Vector(Name(George,W,1), Name(John,A,2))
scala> Await.result(db.run(phones.result), 1000 毫秒) res10: Seq[Example.PhoneTable#TableElementType] = Vector(Phone(+1 301 531 1121,1,1), Phone(+1 301 748 5192,1,2), Phone(+1 301 531 4519,2,3), Phone(+1 202 667 9612,2,4), Phone(+1 202 667 4044,2,5))
scala> Await.result(testContacts, 1000 毫秒) res5: Seq[Contacts.Contact] = 列表()
scala>
感谢任何帮助。这是完整的源代码:
import scala.concurrent.Await
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
import slick.driver.H2Driver.api._
import scala.util.Try
import scala.concurrent.Future
object Contacts extends App {
val db = Database.forConfig("dbconfig")
case class Contact(firstName: String, lastName: String, phones: Seq[String])
def testContacts: Future[Seq[Contact]] = {
names.result.map { namelist =>
var contacts = Seq[Contact]()
for (n <- namelist) {
println("NAME: " + n)
val phoneNumbers = for {
p <- phones.filter(_.nameId === n.id)
} yield p.phoneNumber
phoneNumbers.result.map { plist =>
contacts = contacts :+ Contact(n.firstName, n.lastName, plist)
// Q: HOW DO I RETURN "contacts" to the caller?
println("CONTACTS: " + plist) // THIS IS NOT PRINTED!
}
}
}
Future { Seq[Contact]() } // dummy statement to avoid compilation error
}
case class Name(firstName: String, lastName: String, id: Long = 0L)
class NameTable(tag: Tag) extends Table[Name](tag, "Names") {
def id = column[Long]("ID", O.PrimaryKey, O.AutoInc)
def firstName = column[String]("FIRSTNAME")
def lastName = column[String]("LASTNAME")
override def * = (firstName, lastName, id) <> (Name.tupled, Name.unapply)
}
lazy val names = TableQuery[NameTable]
case class Phone(phoneNumber: String, nameId: Long, id: Long = 0L)
class PhoneTable(tag: Tag) extends Table[Phone](tag, "Phones") {
def id = column[Long]("ID", O.PrimaryKey, O.AutoInc)
def phoneNumber = column[String]("PHONE_NUMBER")
def nameId = column[Long]("NAME")
override def * = (phoneNumber, nameId, id) <> (Phone.tupled, Phone.unapply)
def name_fk = foreignKey("Phones_Names_ID_FK", nameId, names)(_.id, onUpdate = ForeignKeyAction.Cascade, onDelete = ForeignKeyAction.Cascade)
}
lazy val phones = TableQuery[PhoneTable]
def testNames = Seq(
Name("George", "W"),
Name("John", "A"))
def testPhones = Seq(
Phone("+1 301 531 1121", 1L),
Phone("+1 301 748 5192", 1L),
Phone("+1 301 531 4519", 2L),
Phone("+1 202 667 9612", 2L),
Phone("+1 202 667 4044", 2L))
def populate: DBIOAction[Option[Int], NoStream,Effect.All] = {
for {
_ <- names.schema.drop.asTry andThen names.schema.create
_ <- phones.schema.drop.asTry andThen phones.schema.create
nameCount <- names ++= testNames
phoneCount <- phones ++= testPhones
} yield nameCount
}
}
您的 testContacts 查询不是很直接,我会在查询语句中使用连接或过滤器,然后展开行
这是我会尝试的方法
def testContacts: Future[Seq[Contact]] = {
val query = for {
(n, pl) <- names join phones on (_.id === _.nameId)
} yield (n, pl)
db.run(query.result).map { (row) =>
row.groupBy(_._1).map { r =>
val name = r._1
val phones = r._2.map(_._2.phoneNumber)
Contact(name.firstName, name.lastName, phones)
}.toSeq
}
}
这使用巧妙的 forcomp
连接语法,然后映射结果