我有以下查询来获取一个人的所有祖先和后代。好吧,目前只有 祖先或后代。
def relatives = FamilyTree.all.filter(p => p.descendant === id || p.ancestor === id).flatMap(_.descendantFK)
Family Tree表如下所示:
id | ancestor (references id on persons) | descendant (references id on persons)
以上查询为我提供了所有后代,因为它在后代外键上的flatMaps
现在我想一起检索所有祖先和后代!
Flatmap让我在这里遇到麻烦。我怎样才能在descendantFK和ancestorFK上进行flatMap?
基本上我想要的是
....flatMap(r => r.descendantFK || r.ancestorFK)
当然上述情况不起作用。
在SQL中我想要的东西:
SELECT * FROM familyTree WHERE ancestor == id OR descendant == id
编辑:根据请求添加类定义:
case class Person(id: Long, foreName: String, lastName: String)
{
def relatives: Query[Persons, Person, Seq] =
{
for
{
person <- Persons.all.filter(_.id === this.id)
relative <- person.relatives
} yield (relative)
}
}
class Persons(tag: Tag) extends Table[Person](tag, "persons")
{
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def foreName = column[String]("forename")
def lastName = column[String]("lastname")
def * = (id, foreName, lastName) <> (Person.tupled, Person.unapply)
def relatives = PersonFamilyTree.all.filter(c => c.descendant === id || c.ancestor === id).flatMap(t => t.descendantFK)
}
object Persons
{
lazy val all = TableQuery[Persons]
val findById = Compiled {a: Rep[Long] => all.filter(_.id === a)}
}
数据库包装类
class SQLDatabaseWrapper(pathToDatabase: String, driver: String)
{
val db = Database.forURL(pathToDatabase, driver = this.driver)
private val persons = Persons.all
private val familyTree = PersonFamilyTree.all
val setup = DBIO.seq(
// Create the tables, including primary and foreign keys
(persons.schema ++ familyTree.schema).create,
// Insert some dummy data
persons += new Person(-1, "Granpa", ""),
persons += new Person(-1, "Pa", ""),
persons += new Person(-1, "Daughter", ""),
persons += new Person(-1, "Son", ""),
familyTree += new PersonFamilyTreeEntry(-1, 1, 2), // Granpa -> Pa
familyTree += new PersonFamilyTreeEntry(-1, 1, 3), // Granpa -> Daughter
familyTree += new PersonFamilyTreeEntry(-1, 1, 4), // Granpa -> Son
familyTree += new PersonFamilyTreeEntry(-1, 2, 3), // Pa -> Daughter
familyTree += new PersonFamilyTreeEntry(-1, 2, 4) // Pa -> Son
)
val setupFuture = db.run(setup)
def getAllPersons(): Future[Seq[Person]] =
{
db.run(persons.result)
}
def getPerson(id: Long): Future[Person] =
{
// db.run(persons.filter(_.foreName === "Nathanael").result)
db.run(Persons.findById(id).result).map(_.head)
}
def getRelatives(person: Person): Future[Seq[Person]] =
{
val relativesQuery: Query[Persons, Person, Seq] = person.relatives
db.run(relativesQuery.result)
// db.run(person.familyMembers.result)
}
case class PersonFamilyTreeEntry(id: Long, ancestor: Long, descendant: Long)
class PersonFamilyTree(tag: Tag) extends Table[PersonFamilyTreeEntry](tag, "person_family_tree")
{
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def ancestor = column[Long]("ancestor")
def descendant = column[Long]("descendant")
def * = (id, ancestor, descendant) <> (PersonFamilyTreeEntry.tupled, PersonFamilyTreeEntry.unapply _)
def ancestorFK = foreignKey("ancestor_fk", ancestor, Persons.all)(_.id)
def descendantFK = foreignKey("descendant_fk", descendant, Persons.all)(_.id)
}
object PersonFamilyTree
{
lazy val all = TableQuery[PersonFamilyTree]
}
}
这就是我在其他地方查询(或手动测试)的方式:
val pa: Future[Person] => sqlDatabaseWrapperInstance.getPerson(2)
pa.onSuccess{
case p: Person =>
{
val relativesOfPa = sqlDatabaseWrapperInstance.getRelatives(p)
relativesOfPa.onSuccess
{
case r: Seq[Person] => r foreach(println(_))
}
}
}
答案 0 :(得分:2)
您应该能够使用++
(unionAll
)来完成此操作:
....flatMap(r => r.descendantFK ++ r.ancestorFK)
以另一种方式思考这个问题,你可以通过加入来做到这一点:
for {
person <- Person.all
other <- FamilyMember.all
if (other.ancestor === person.id && other.ancestor === id)
|| (other.descendant === person.id && other.descendant === id)
} yield person
您也可以使用带有子查询的in
来执行此操作:
val familyMembers = FamilyTree.all
.filter(p => p.descendant === id || p.ancestor === id)
.map(p => if (p.descendant === id) p.descendant else p.ancestor)
Persons.all.filter(_.id in familyMembers)