MongoDB-Scala-Play:写入/读取复合ID

时间:2013-10-10 13:51:45

标签: mongodb scala playframework securesocial salat

我刚将我的应用程序移植到Play 2.2并修改了一些代码以使用最新版本的SecureSocial - 我看到案例类UserId已重命名为{{1} }}。好吧,我能够注册一个新用户......并且数据已成功保存到MongoDB:

IdentityId

...但是一旦我尝试登录 - 当然这意味着从MongoDb读取数据,玩具就不再起作用了。由于未从数据库中读取数据,我总是得到> db.identities.find() { "_id" : ObjectId("5256a6ffe4b000f9ba0b6ce5"), "identityId" : { "userId" : "joey", "providerId" : "userpass" }, "firstName" : "Joey", "lastName" : "Smith", "fullName" : "Joey Smith", "email" : "joey@mydomain.com", "authMethod" : { "method" : "userPassword" }, "passwordInfo" : { "hasher" : "bcrypt", "password" : "$2a$10$vDr02XZ5dAHmJHDexbBnROWejhtnYFufPJtHPr8IT.rqsCSAAu5Ju" } }

以下是我的完整代码:

NoSuchElementException

正如您所看到的,我正在使用复合键...所以也许我在方法import com.mongodb.casbah.Imports._ import com.novus.salat._ import com.novus.salat.annotations._ import com.novus.salat.dao._ import play.api.Play.current import play.api.libs.json._ import play.api.libs.functional.syntax._ import securesocial.core._ import se.radley.plugin.salat._ import se.radley.plugin.salat.Binders._ import mongodbContext._ /** * Defines an account identity to be used by [[securesocial.core.SecureSocial]] * when signing up or signing in. @see securesocial.core.Identity. */ case class AccountIdentity( identityId: IdentityId, firstName: String, lastName: String, fullName: String, email: Option[String], avatarUrl: Option[String], authMethod: AuthenticationMethod, oAuth1Info: Option[OAuth1Info] = None, oAuth2Info: Option[OAuth2Info] = None, passwordInfo: Option[PasswordInfo] = None ) extends Identity /** * Provides database access and serialization for [[AccountIdentity]] data. */ object AccountIdentity extends (( IdentityId, String, String, String, Option[String], Option[String], AuthenticationMethod, Option[OAuth1Info], Option[OAuth2Info], Option[PasswordInfo]) => AccountIdentity) with AccountIdentityDAO with SocialUserJson { /** * Returns an `AccountIdentity` initialized with the specified identity. * * @param identity The identity that Initializes the `AccountIdentity`. */ def apply(identity: Identity) : AccountIdentity = { AccountIdentity( identity.identityId, identity.firstName, identity.lastName, identity.fullName, identity.email, identity.avatarUrl, identity.authMethod, identity.oAuth1Info, identity.oAuth2Info, identity.passwordInfo ) } } /** * Provides database access for [[AccountIdentity]] data. */ trait AccountIdentityDAO extends ModelCompanion[AccountIdentity, IdentityId] { private def collection = mongoCollection("identities") val dao = new SalatDAO[AccountIdentity, IdentityId](collection) {} collection.ensureIndex(DBObject("email" -> 1, "_id.providerId" -> 1), "emailProvider", unique = true) /** * Finds the [[AccountIdentity]] identified by the specified identity id. * * @param identityId The identity id. * @return An `Option` value containing the `AccountIdentity`, or `None` * if there is no `AccountIdentity` identified by `identityId`. */ def find(identityId: IdentityId): Option[AccountIdentity] = { dao.findOne(DBObject("_id.userId" -> identityId.userId, "_id.providerId" -> identityId.providerId)) } /** * Finds the [[AccountIdentity]] identified by the specified email and provider id. * * @param email The user email. * @param providerId The provider id. * @return An `Option` value containing the `AccountIdentity`, or `None` if * there is no `AccountIdentity` associated with `email` and `providerId`. */ def findByEmailAndProvider(email: String, providerId: String): Option[AccountIdentity] = { dao.findOne(DBObject("email" -> email, "_id.providerId" -> providerId)) } } /** * Provides functionality for serializing/deserializing [[AccountIdentity]] * data to/from JSON. */ trait SocialUserJson { import IdentityId._ import AuthenticationMethod._ import OAuth1Info._ import OAuth2Info._ import PasswordInfo._ /** * An [[AccountIdentity]] serialized to JSON. */ implicit val identityJsonWrite = new Writes[AccountIdentity] { def writes(identity: AccountIdentity): JsValue = { Json.obj( "identityId" -> identity.identityId, "firstName" -> identity.firstName, "lastName" -> identity.lastName, "fullName" -> identity.fullName, "email" -> identity.email, "avatarUrl" -> identity.avatarUrl, "authMethod" -> identity.authMethod, "oAuth1Info" -> identity.oAuth1Info, "oAuth2Info" -> identity.oAuth2Info, "passwordInfo" -> identity.passwordInfo ) } } /** * An [[AccountIdentity]] deserialized from JSON. */ implicit val identityJsonRead = ( (__ \ 'identityId).read[IdentityId] ~ (__ \ 'firstName).read[String] ~ (__ \ 'lasttName).read[String] ~ (__ \ 'fullName).read[String] ~ (__ \ 'email).readNullable[String] ~ (__ \ 'avatarUrl).readNullable[String] ~ (__ \ 'authMethod).read[AuthenticationMethod] ~ (__ \ 'oAuth1Info).readNullable[OAuth1Info] ~ (__ \ 'oAuth2Info).readNullable[OAuth2Info] ~ (__ \ 'passwordInfo).readNullable[PasswordInfo] )(AccountIdentity) } find中做错了。

EDIT1: ...当然,我还为findByEmailAndProvider实现了序列化/反序列化:

IdentityId

1 个答案:

答案 0 :(得分:0)

发现...我只需要将identityId重新映射到_id

import com.novus.salat._
import com.mongodb.casbah.Imports._

import play.api.Play
import play.api.Play.current

/**
 * Defines a custom Salat context for MongoDB.
 */
package object mongodbContext {

  /**
   * The custom context that globally overrides the Salat defaults.
   */
  implicit val context = {
    val context = new Context {
      val name = "global"
      override val typeHintStrategy = StringTypeHintStrategy(when = TypeHintFrequency.WhenNecessary, typeHint = "_t")
    }

    context.registerGlobalKeyOverride(remapThis = "identityId", toThisInstead = "_id")
    context.registerClassLoader(Play.classloader)
    context
  }
}

...最终数据库中的数据是正确的:

> db.identities.find()
{ "_id" : { "userId" : "joey", "providerId" : "userpass" }, "firstName" : "Joey", "lastName" : "Smith", "fullName" : "Joey Smith", "email" : "joey@mydomain.com", "authMethod" : { "method" : "userPassword" }, "passwordInfo" : { "hasher" : "bcrypt", "password" : "$2a$10$lWxiZz3XJcj3ckOOTTgleOo3tBy2zZvO.LfX9jeUtatHENcTHQ.hS" } }