使用 SORM 持久化递归数据模型

Posted

技术标签:

【中文标题】使用 SORM 持久化递归数据模型【英文标题】:Persisting a recursive data model with SORM 【发布时间】:2016-06-02 12:34:18 【问题描述】:

对于我的项目,我想做一个树模型;假设它是关于文件和目录的。但是文件可以同时位于多个目录中,所以更像是在 gmail 中为电子邮件添加标签的方式。 我想建立一个能力模型(比如java、scala、angular等)并将它们分类。在这种情况下,java 和 scala 是语言,agila 和 scrum 是工作方式,angular 是框架/工具包等等。但是我们想灵活地对东西进行分组,即 play、java 和 scala 属于“后端”类别,而 angular、jquery 等属于前端类别。

我想我会有这样的表权限:

case class Competence (name: String, categories: Option[Category])

分类如下:

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

这将编译,但 SORM 会生成错误(来自激活器控制台):

scala> import models.DB
import models.DB
scala> import models.Category
import models.Category
scala> import models.Competence
import models.Competence
scala> val cat1 = new Category ( "A", None )
cat1: models.Category = Category(A,None)
scala> val sav1 = DB.save ( cat1 )
sorm.Instance$ValidationException: Entity 'models.Category' recurses at 'models.Category'
  at sorm.Instance$Initialization$$anonfun$2.apply(Instance.scala:216)
  at sorm.Instance$Initialization$$anonfun$2.apply(Instance.scala:216)
  at scala.Option.map(Option.scala:146)
  at sorm.Instance$Initialization.<init>(Instance.scala:216)
  at sorm.Instance.<init>(Instance.scala:38)
  at models.DB$.<init>(DB.scala:5)
  at models.DB$.<clinit>(DB.scala)
  ... 42 elided

虽然我想要 sorm 的美观简洁,但我是否需要切换到 Slick 来让我的项目实现它?我的想法是链接表将由 sorm 隐式生成。或者我可以简单地通过以下方式解决这个问题:

case class Taxonomy ( child: Category, parent: Category )

然后在 JS 端进行解析/格式化工作?似乎让使用 sorm 的简单性消失了一些。

为了给出一些想法,我想要的是制作一个 ajaxy 页面,用户可以在左侧列表中添加新的能力,然后将它们链接/取消链接到树中他喜欢的任何类别标签。

【问题讨论】:

【参考方案1】:

我遇到了同样的问题。我需要定义两个操作数之间的交互,可以链接(递归)。喜欢:

case class InteractionModel(
    val leftOperantId: Int,
    val operation: String ,
    val rightOperantId: Int,
    val next: InteractionModel)

我的解决方法:将此案例类更改为 Json(String) 并将其作为字符串保存,当检索它时,将其从 Json 转换。而且既然是String,就不要注册为sorm Entity。

import spray.json._
case class InteractionModel(
    val leftOperantId: Int,
    val operation: String ,
    val rightOperantId: Int,
    val next: InteractionModel) extends Jsonable 
  def toJSON: String = 
    val js = this.toJson(InteractionModel.MyJsonProtocol.ImJsonFormat)
    js.compactPrint
  


//define protocol
object InteractionModel 
  def fromJSON(in: String): InteractionModel = 
    in.parseJson.convertTo[InteractionModel](InteractionModel.MyJsonProtocol.ImJsonFormat)
  

  val none = new InteractionModel((-1), "", (-1), null) 
    override def toJSON = ""
  

  object MyJsonProtocol extends DefaultJsonProtocol 
    implicit object ImJsonFormat extends RootJsonFormat[InteractionModel] 
      def write(im: InteractionModel) = 
        def recWrite(i: InteractionModel): JsObject = 
          val next = i.next match 
            case null  => JsNull
            case iNext => recWrite(i.next)
          
          JsObject(
            "leftOperantId" -> JsNumber(i.leftOperantId),
            "operation" -> JsString(i.operation.toString),
            "rightOperantId" -> JsNumber(i.rightOperantId),
            "next" -> next)
        
        recWrite(im)
      
      def read(value: JsValue) = 
        def recRead(v: JsValue): InteractionModel = 
          v.asJsObject.getFields("leftOperantId", "operation", "rightOperantId", "next") match 
            case Seq(JsNumber(left), JsString(operation), JsNumber(right), nextJs) =>
              val next = nextJs match 
                case JsNull => null
                case js     => recRead(js)
              
              InteractionModel(left.toInt, operation, right.toInt, next)
            case s => InteractionModel.none
          
        
        recRead(value)
      
    
  

【讨论】:

或者使用uPickle进行JSON转换。

以上是关于使用 SORM 持久化递归数据模型的主要内容,如果未能解决你的问题,请参考以下文章

如何从 SORM 表定义中排除类字段?

SORM 持久化 'id' 未定义

数据持久化

SORM:尝试引用一个未持久化的实体

MyBatis

具有单个持久存储协调器的多个数据模型