2016-06-02 6 views
1

Für mein Projekt möchte ich ein Baummodell erstellen; Sagen wir, es geht um Dateien und Verzeichnisse. Dateien können sich jedoch gleichzeitig in mehreren Verzeichnissen befinden. Sie können also ähnlich wie E-Mails in Google Mail Tags hinzufügen. Ich möchte ein Modell für Kompetenzen (sagen wir Java, Scala, eckig usw.) erstellen und in Kategorien einteilen. In diesem Fall sind Java und Scala Sprachen, Agila und Scrum sind Arbeitsweisen, eckig ist ein Framework/Toolkit und so weiter. Aber dann wollen wir Sachen flexibel gruppieren, dh play, java und scala sind in einer 'Backend' Kategorie und angular, jquery, etc sind in einer Frontend Kategorie.Ein rekursives Datenmodell mit SORM beibehalten

Ich dachte, ich würde eine Tabelle Kompetenzen haben wie so:

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

und die Kategorien wie folgt:

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

Dies kompiliert, aber SORM einen Fehler (von Aktivator-Konsole) erzeugen :

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 

Obwohl ich die schöne Einfachheit von Sorm will, muss ich zu Slic wechseln k für mein Projekt, um dies zu implementieren? Ich hatte die Idee, dass Link-Tabellen implizit von Sorm generiert würden. Oder könnte ich einfach um das Problem herum arbeiten, indem ich ein:

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

machen und dann auf der JS-Seite parsing/Formatierung arbeiten? Es scheint, dass die Einfachheit der Verwendung von Sorm etwas verschwindet.

Um eine Idee zu geben, was ich will, ist eine Ajaxy-Seite, wo ein Benutzer neue Kompetenzen in einer Liste auf der linken Seite hinzufügen kann, und verknüpfen Sie sie dann zu jedem Kategorie-Tag in der Struktur, die er mag.

Antwort

1

Ich stieß auf die gleiche Frage. Ich musste eine Interaktion zwischen zwei Operanten definieren, die verkettet (rekursiv) sein kann. Wie:

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

Meine Arbeit um: diesen Fall Klasse ändern in Json (String) und bleiben es als String, wenn retreiving, konvertieren von Json. Und da es String ist, registrieren Sie es nicht als 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) 
     } 
    } 
    } 
} 
+0

oder [uPickle] (http://www.lihaoyi.com/upickle-pprint/upickle/) die JSON Konvertierung. – keos