2016-07-13 9 views
0

Ich habe eine sehr einfache Datenbanktabelle namens Regionen, in denen jede Region eine übergeordnete Region haben kann.Erstellen Sie ein rekursives Objektdiagramm aus einem Tupel mit Scala

mysql> describe region; 
+---------------+-------------+------+-----+---------+-------+ 
| Field   | Type  | Null | Key | Default | Extra | 
+---------------+-------------+------+-----+---------+-------+ 
| region_code | char(3)  | NO | PRI | NULL |  | 
| region_name | varchar(50) | NO |  | NULL |  | 
| parent_region | char(3)  | YES | MUL | NULL |  | 
+---------------+-------------+------+-----+---------+-------+ 

Nun möchte Ich mag diese Daten an einen Scala Objektgraph von Fallklassen hydratisieren, die jeweils einen Elternteil des gleichen Typs haben.

case class Region(code: String, name: String, parent: Option[Region]) 

Ich mache dies mit dem folgenden Code. Es funktioniert, aber es erstellt doppelte Objekte, die ich wenn möglich vermeiden möchte.

Ich weiß, wie man dies in der imperativen Weise tut, aber nicht den funktionalen Weg. Ich weiß, dass es einen expressiven Weg geben muss, dies mit Rekursion zu tun, aber ich kann es nicht herausfinden. Weißt du wie? Vielen Dank!

+0

können Sie einen Blick auf https://github.com/cchantep/acolyte/tree/10m-anorm-tutorial – cchantep

+0

Danke für den Link (und den Code-Schnipsel Reinigung), aber das ist nicht ganz das, was Ich suchte. Das Beispiel zeigt eine hierarchische Datenstruktur, nicht eine rekursive. Keine der Fallklassen bezieht sich auf Instanzen von sich selbst. –

Antwort

0

Ich konnte dieses Problem lösen, indem ich die Region-Fallklasse so umstrukturiere, dass die übergeordnete Region eine Variable ist und eine Sammlung von untergeordneten Elementen hinzufügt. Es wäre schön, dies ohne Var zu machen, aber naja.

case class Region(code: String, name: String, subRegions: Seq[Region]){ 
    var parentRegion: Option[Region] = None 
    subRegions.foreach(_.parentRegion = Some(this)) 
} 

Die Rekursion ist natürlicher von der Wurzel nach unten.

def getAll(): Seq[Region] = { 

    Logger.debug("Getting all regions.") 
    db.withConnection { implicit conn => 

    val parser = for { 
    code <- str("region_code") 
    name <- str("region_name") 
    parent <- str("parent_region").? 
    } yield (code, name, parent) 

    val results = SQL("SELECT region_code, region_name, parent_region from region").as(parser.*) 

    def toRegion(record: (String, String, Option[String])): Region = { 
    val (regionCode, name, parent) = record 
    val children = results.filter(_._3 == Some(regionCode)).map(toRegion) 
     Region(regionCode, name, children) 
    } 

    val rootRegions = results filter(_._3 == None) map toRegion 

    rootRegions.foreach(r => Logger.debug("region: " + r)) 

    rootRegions 
    } 
}