2016-07-13 6 views
0

私は、各領域に親領域がある可能性がある非常に単純なデータベーステーブルを持っています。スカラでタプルから再帰オブジェクトグラフを作成

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 |  | 
+---------------+-------------+------+-----+---------+-------+ 

ここでは、このデータを、それぞれが同じタイプの親を持つケースクラスのScalaオブジェクトグラフに含めることにしたいと思います。

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

これは次のコードで行います。それは動作しますが、可能であれば避けたい複製オブジェクトを作成します。

class RegionDB @Inject() (db: Database) { 
    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.*) 

     // TODO: Change this so it doesn't create duplicate records 
     def toRegion(record: (String, String, Option[String])): Region = { 
     val (code, name, parent) = record 
     val parentRecord = parent.map(p => results.find(_._1 == p)).getOrElse(None) 
     new Region(code, name, parentRecord.map(toRegion).orElse(None)) 
     } 

     val regions = results map toRegion 

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

     regions 
    } 
    } 
} 

私は命令的な方法でこれを行う方法を知っていますが、機能的な方法ではありません。私は再帰でこれを行うための表現的な方法が必要であることを知っていますが、私はそれを理解することはできません。どのようにするか知っていますか?ありがとう!

+0

あなたは、リンクいただきありがとうございます(とコードスニペットをクリーンアップ)https://github.com/cchantep/acolyte/tree/10m-anorm-tutorial – cchantep

+0

を見てすることができますが、それはかなり何がありません私は探していた。この例では階層的なデータ構造を示していますが、再帰的な構造はありません。どのクラスも、それらのインスタンスを参照するものはありません。 –

答えて

0

私はこの問題を解決するために、Regionのcaseクラスを再構築して、親リージョンがvarで、子のコレクションを追加することができました。それはvarなしでこれを行うことはうれしいですが、ああよく。

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

再帰はルートからダウンする方が自然です。

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 
    } 
} 
関連する問題