3

私は Rails から来た新しいプロジェクトのために Scala を学んでいます。基本的に「属性」のコレクションと考えることができる多くのモデルで使用されるタイプを定義しました。これは基本的に、ほとんどの責任を委任するハッシュマップの単なるラッパーです。

case class Description(attributes: Map[String, String]) {

  override def hashCode: Int = attributes.hashCode

  override def equals(other: Any) = other match {
    case that: Description => this.attributes == that.attributes
    case _ => false
  }
}

したがってDescription、次のようなを使用してモデル クラスを定義します。

case class Person(val name: String, val description: Description)

ただし、PersonSalatDAO を使用して永続化すると、次のようなドキュメントになります。

{
  name : "Russell",
  description: 
  {
    attributes: 
    {
      hair: "brown",
      favourite_color: "blue"
    }
  }
}

実際には、attributesタグ内のdescriptionタグのネストが必要ない場合-実際に欲しいのはこれです:

{
  name : "Russell",
  description: 
  {
    hair: "brown",
    favourite_color: "blue"
  }
}

私は試していませんが、 aを含むのではなくDescriptiona を拡張した場合、それを機能させることができると思いますが、 aは の型ではないため、それはaおよびそれ自体の他の動作については、後で追加します。継承より合成など。MapDescriptionMapMap

だから私の質問は、どうすれば Salat (または Casbah、私はそれらを使い始めたばかりなので、どちらが変換を行っているかについては実際には少し不明です) に、Descriptionクラスをシリアル化および逆シリアル化する方法を伝えることができますか? ここのcasbahチュートリアルでは、次のように述べています。

独自のカスタム タイプのシリアライザーとデシリアライザーを作成することもできます。カスタムシリアライザーとデシリアライザーを参照してください。

しかし、このページは存在しないようです。それとも、間違った方法で進んでいますか?これが私がやりたいこと、注釈などであることを示す本当に簡単な方法は実際にありますか? または、シリアライゼーションを何らかの方法で属性マップに委任することはできますか?

編集: JodaTime 変換ヘルパーのソースを見た後、次のことを試しましたが、まだ動作させることができませんでした:

import org.bson.{ BSON, Transformer }
import com.mongodb.casbah.commons.conversions.MongoConversionHelper

object RegisterCustomConversionHelpers extends Serializers
  with Deserializers {
  def apply() = {
    super.register()
  }
}

trait Serializers extends MongoConversionHelper
  with DescriptionSerializer {

  override def register() = {
    super.register()
  }
  override def unregister() = {
    super.unregister()
  }
}

trait Deserializers extends MongoConversionHelper {
  override def register() = {
    super.register()
  }
  override def unregister() = {
    super.unregister()
  }
}

trait DescriptionSerializer extends MongoConversionHelper {
  private val transformer = new Transformer {
    def transform(o: AnyRef): AnyRef = o match {
      case d: Description => d.attributes.asInstanceOf[AnyRef]
      case _ => o
    }
  }

  override def register() = {
    BSON.addEncodingHook(classOf[Description], transformer)
    super.register()
  }
}

呼び出しRegisterCustomConversionHelpers()てから保存するPersonと、エラーは発生しません。効果がなく、これまでと同じ方法でドキュメントを保存します。これはまた、私が望むことのためにしなければならないことがかなり多いようです。

4

2 に答える 2

4

Salat メンテナーはこちら。

ここでのラッパーとしての Description の価値がわかりません。属性のマップをラップし、ケース クラスのデフォルトの equals と hashcode impl をオーバーライドします。これは、impl がとにかくマップに委譲され、ケース クラスがとにかく行うことなので、不要に思えます。シリアル化されたオブジェクト。

あなたはただ考えましたか:

case class Person(val name: String, val description: Map[String, String])

これにより、箱から出してすぐに必要なことが正確に行われます。

別の状況では、シンプルなタイプ エイリアスをお勧めしますが、残念ながら、ピクルス化された Scala シグネチャでの表現方法に問題があるため、Salat は現在タイプ エイリアスをサポートできません。

(簡潔にするために例からこれを省略した可能性がありますが、Mongo モデルに _id フィールドを設定するのがベスト プラクティスです。設定していない場合は、Mongo Java ドライバーが提供します)

salat-core テスト パッケージ (java.net.URL を処理する) には、カスタム BSON フックの実例があります。適切な場所に登録していないという理由だけで、フックが機能していない可能性がありますか? それでも、上記の例から明らかではない値を追加しない限り、 Description を削除することをお勧めします。

于 2012-03-02T13:26:51.003 に答える
0

@prasinousの回答に基づいて、これはそれほど簡単ではないと判断したため、デザインを次のように少し変更しました。これにより、必要なものがほとんど得られます。をフィールドとして永続化するのではなくDescription、バニラ マップを永続化しDescribedてから、説明が必要なモデル クラスに特性を混ぜます。これDescriptionにより、オブジェクトの作成時にマップが自動的に変換されます。誰かがこのアプローチの明らかな問題や改善のための提案を指摘できれば幸いです。

class Description(val attributes: Map[String, String]){
  //rest of class omitted
}

trait Described {
  val attributes: Map[String, String]
  val description = new Description(attributes)
}

case class Person(name: String, attributes: Map[String, String]) extends Described
于 2012-03-02T16:05:27.203 に答える