2015-05-14 125 views
2

我想弄清楚如何將我自己的閉包表實現從另一種語言轉移到斯卡拉並記住。油滑3交易

我有兩個模型,一個Node(id | parentID)和一個NodeTree(id | ancestor |後代),其中每個條目類似於樹中的一條邊。

對於每一個新的節點,我必須做到以下幾點: 查詢所有祖先(或過濾TableQuery他們的),然後添加一個NodeTree入境(邊緣)的每個祖先

感謝豹我目前爲止:

private val nodes = TableQuery[Nodes] 

override def create(node: Node): Future[Seq[Int]] = 
    { 
     val createNodesAction = (
      for 
      { 
       parent <- nodes 
       node <- (nodeTrees returning nodeTrees.map(_.id) into ((ntEntry, ntId) => ntEntry.copy(id = Some(ntId))) += NodeTree(id = None, ancestor = parent.id, descendant = node.id, deleted = None, createdAt = new Timestamp(now.getTime), updatedAt = new Timestamp(now.getTime))) 
      } yield (node) 
     ).transactionally 

     db run createNodesAction 
    } 

但是,這會產生一個類型不匹配;

類型不匹配;發現:slick.lifted.Rep [龍]要求:選項[龍]

再次

:所有我想要做的是:對於每一個parentNode(=每個父母的父母,直到最後一個祖先節點沒有父! )我想在nodeTree中創建一個條目,以便稍後我可以通過另一個通過NodeTree-Table進行過濾的方法調用輕鬆獲取所有後代和祖先。

(只是一閉包表,真的)

編輯:這是我的模型

case class Node(id: Option[Long], parentID: Option[Long], level: Option[Long], deleted: Option[Boolean], createdAt: Timestamp, updatedAt: Timestamp) 

class Nodes(tag: Tag) extends Table[Node](tag, "nodes") 
{ 
    implicit val dateColumnType = MappedColumnType.base[Timestamp, Long](d => d.getTime, d => new Timestamp(d)) 

    def id = column[Long]("id", O.PrimaryKey, O.AutoInc) 
    def parentID = column[Long]("parent_id") 
    def level = column[Long]("level") 
    def deleted = column[Boolean]("deleted") 
    def createdAt = column[Timestamp]("created_at") 
    def updatedAt = column[Timestamp]("updated_at") 

    def * = (id.?, parentID.?, level.?, deleted.?, createdAt, updatedAt) <> (Node.tupled, Node.unapply) 
} 

case class NodeTree(id: Option[Long], ancestor: Option[Long], descendant: Option[Long], deleted: Option[Boolean], createdAt: Timestamp, updatedAt: Timestamp) 

class NodeTrees(tag: Tag) extends Table[NodeTree](tag, "nodetree") 
{ 
    implicit val dateColumnType = MappedColumnType.base[Timestamp, Long](d => d.getTime, d => new Timestamp(d)) 

    def id = column[Long]("id", O.PrimaryKey, O.AutoInc) 
    def ancestor = column[Long]("ancestor") 
    def descendant = column[Long]("descendant") 
    def deleted = column[Boolean]("deleted") 
    def createdAt = column[Timestamp]("created_at") 
    def updatedAt = column[Timestamp]("updated_at") 

    def * = (id.?, ancestor.?, descendant.?, deleted.?, createdAt, updatedAt) <> (NodeTree.tupled, NodeTree.unapply) 
} 

我想要做的就是填充它時自動邊緣(nodeTree)封閉表(http://technobytz.com/closure_table_store_hierarchical_data.html)我創建一個節點。所以我不想手動將所有這些條目添加到數據庫中,但是當我在級別5上創建節點時,我想要自動創建整個路徑(= nodetree-table中的條目)。

我希望清除的東西了一下:)

回答

2

試試這個:

override def create(node: Node): Future[Seq[Int]] = 
{ 
    val parents = getAllParents(node) 
    val createNodesAction = (
     for { 
     parent <- parents 
     node <- nodeTrees += NodeTree(id = None, ancestor = parent.id, descendant = node.id) 
     } yield (node) 
    ).transactionally 

    db run createNodesAction 
} 

你不應該分開單獨獲取的父母。它可以在同一個會話中完成。在上面,你可以很容易地用你想要工作的TableQuery替換'父母'以便理解(有或沒有過濾器)。

另請注意,這裏您將返回受插入操作影響的行數序列。要改爲返回節點ID列表(假設你會標註節點ID爲AUTO_INC以dB爲單位),那麼你可以做這樣的事情:

override def create(node: Node): Future[Seq[Int]] = 
{ 
    val createNodesAction = (
     for { 
     parent <- parents 
     node <- (nodeTrees returning nodeTrees.map(_.id) into ((ntEntry, ntId) => ntEntry.copy(id = Some(ntId))) += NodeTree(id = None, ancestor = parent.id, descendant = node.id) 
     } yield (node) 
    ).transactionally 

    db run createNodesAction 
} 

的區別是:(nodeTrees返回nodeTrees.map(_。 id)到((ntEntry,ntId)=> ntEntry.copy(id =一些(ntId)))而不是隻是(nodeTrees)檢索並將auto inc id映射到結果中。


更新:試試這個:

override def create(node: Node): Future[Seq[Int]] = 
{ 
    def createNodesAction(parentId: Long): DBIOAction[NodeTree, NoStream, Read with Write] = (
     for { 
     node <- (nodeTrees returning nodeTrees.map(_.id) into ((ntEntry, ntId) => ntEntry.copy(id = Some(ntId))) += NodeTree(id = None, ancestor = parentId, descendant = node.id) 
     } yield (node) 
    ).transactionally 

    // TODO: Init and pass in 'parents' 
    db.run(DBIO.sequence(parents.map(createNodesAction(_.id))) 
} 
+0

我會接受你的答案,但有幾個問題:第一:nt.id = ntId - > ntld是類型Long,而Option [Long]在這裏需要。另外,nt.id = ntId - >重新分配給val:/另外,請你詳細說明一下...表單查詢是否會更新(如果有更多的條目存在,它會重新安裝嗎?),還是我需要手動執行? – Sorona

+0

編輯瞭解決設置可選值並重新分配爲val問題的答案。在您選擇insert_上的多個條目的問題上,我無法找到一種方法來做到這一點。這可能是因爲ID可能是使用其他SQL構造([last_insert_id](https://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id))檢索到的。目前,爲了從插入的行中選擇其他項目(如時間戳),我通過對檢索到的ID運行選擇查詢來手動完成。 – panther

+0

value id不是List的成員[models.Node] * sighs *我必須解壓縮列表,甚至壓扁它?如果我用TableQuery嘗試它,我甚至會得到:type mismatch;找到:slick.lifted.Rep [Long] required:Option [Long] – Sorona

1

嘗試改變這一行。

node <- (nodeTrees returning nodeTrees.map(_.id) into ((ntEntry, ntId) => ntEntry.copy(id = ntId)) += NodeTree(id = None, ancestor = parent.id, descendant = node.id, deleted = None, createdAt = new Timestamp(now.getTime), updatedAt = new Timestamp(now.getTime))) 

它是否解決了這個問題?很難從你的問題中確切地知道你的模型是什麼。

+1

我在問題中添加了我的模型代碼,但我不明白這應該如何幫助。無論如何,我還添加了另一個關於我究竟想達到什麼的描述。無論如何,感謝您的幫助! :) – Sorona