2015-05-14 81 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