使用Slick 3.1与play和scala映射Enumeration时“注入构造函数时出错”

时间:2015-11-03 22:24:53

标签: scala playframework guice slick

我有以下课程。请注意已注释掉的角色行。

用户模型:

case class User(
  uid: Option[Long] = None,
//  role: Option[Role.Role] = None,
  firstName: String,
  lastName: String,
  middleName: Option[String] = None,
  email: String,
  avatarUrl: Option[String],
  created: DateTime = DateTime.now,
  modified: DateTime = DateTime.now
)

UserComponent和UserDAO:

import javax.inject._
import scala.concurrent.Future
import org.krazykat.whatsupdoc.models.User
import play.api.db.slick.{HasDatabaseConfigProvider, DatabaseConfigProvider}
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import slick.driver.{JdbcProfile, JdbcDriver}
import org.joda.time.DateTime
import com.github.tototoshi.slick.GenericJodaSupport
import java.sql.Time

trait UsersComponent { self: HasDatabaseConfigProvider[JdbcProfile]  =>
  import driver.api._

  object PortableJodaSupport extends GenericJodaSupport(driver.asInstanceOf[JdbcDriver])
  import PortableJodaSupport._


//  implicit val roleMapper = MappedColumnType.base[Role.Role, String](
//    e => e.toString,
//    s => Role.withName(s)
//  )


  class Users(tag: Tag) extends Table[User](tag, "USERS") {

    def uid = column[Long]("USER_ID", O.PrimaryKey, O.AutoInc)
//    def role = column[Role.Role]("ROLE") 
    def firstName = column[String]("FIRST_NAME")
    def lastName = column[String]("LAST_NAME")
    def middleName = column[String]("MIDDLE_NAME")
    def email = column[String]("EMAIL")
    def avatarUrl = column[String]("AVATAR_URL")
    def created =  column[DateTime]("CREATED")
    def modified = column[DateTime]("MODIFIED")

    def * = (uid.?, firstName, lastName, middleName.?, email, avatarUrl.?, created, modified) <> (User.tupled, User.unapply _)
  }
}


/**
 * @author ehud
 */
@Singleton
class UsersDAO @Inject()(protected val dbConfigProvider: DatabaseConfigProvider) extends UsersComponent with HasDatabaseConfigProvider[JdbcProfile] {
  import driver.api._

  val users = TableQuery[Users]

  def count = db.run(users.length.result)

  def getById(uid: Long) = 
    db.run(users.filter(_.uid === uid).result.headOption)

  def insert(user: User) =
    db.run((users returning users.map(_.uid)) += user).map(id => id)

  def delete(user: User) =
    db.run(users.filter(_.uid === user.uid).delete)

  def update(uid: Long, user: User) = {
    val userToUpdate: User = user.copy(Some(uid))
    db.run(users.filter(_.uid === uid).update(userToUpdate))
  }
}

和测试规范:

class UsersSpec extends Specification {


  def dateIs(date: java.util.Date, str: String) = new java.text.SimpleDateFormat("yyyy-MM-dd").format(date) == str

  trait WithDatabaseConfig {
    lazy val (driver, db) = {
      val dbConfig = DatabaseConfigProvider.get[JdbcProfile](Play.current)
      (dbConfig.driver, dbConfig.db)
    }
  }

  "User model" should {   
    def usersDao(implicit app: Application) = {
      val app2UsersDAO = Application.instanceCache[UsersDAO]
      app2UsersDAO(app)
    }

    "be inserted to db correctly" in new WithApplication with WithDatabaseConfig {
      import driver.api._

      val userInsertresult = Await.result(usersDao.insert(
        User(None, "firstname", "lastname", Some("middlename"), "me@me.com", Some("avatar"), DateTime.now, DateTime.now)), 
        Duration.Inf
      )
      val count = Await.result(usersDao.count, Duration.Inf)
      count mustEqual 1
    }

当我运行此规范时,它会成功。大。

现在我想为我的用户添加一个角色。所以我创建了以下Role类:

object Role extends Enumeration{

  type Role = Value

  val None = Value("NONE")
  val Admin = Value("ADMIN")
  val Root = Value("ROOT")
} 

并取消注释相关行(并将其添加到任何instanciation调用),并更新evolutions文件(Role部分存储为VARCHAR)。现在,当规范运行时,我得到以下异常:

[error]   ! be inserted to db correctly
[error]    Unable to provision, see the following errors:
[error]    
[error]    1) Error injecting constructor, java.lang.NullPointerException
[error]      at UsersDAO.<init>(UsersDAO.scala:59)
[error]      at UsersDAO.class(UsersDAO.scala:59)
[error]      while locating UsersDAO
[error]    
[error]    1 error (InjectorImpl.java:1025)
[error] com.google.inject.internal.InjectorImpl$2.get(InjectorImpl.java:1025)
[error] com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1051)
[error] play.api.inject.guice.GuiceInjector.instanceOf(GuiceInjectorBuilder.scala:321)
[error] play.api.inject.guice.GuiceInjector.instanceOf(GuiceInjectorBuilder.scala:316)
[error] play.api.Application$$anonfun$instanceCache$1.apply(Application.scala:234)
[error] play.api.Application$$anonfun$instanceCache$1.apply(Application.scala:234)
[error] play.utils.InlineCache.fresh(InlineCache.scala:69)
[error] play.utils.InlineCache.apply(InlineCache.scala:55)

我尝试在线进行研究,但是我发现的关于如何进行枚举的所有Slick样本看起来都像我的,并且注入错误没有出现在Slick上下文中。

任何想法?

2 个答案:

答案 0 :(得分:2)

此处的问题是您尝试使用driver.api.MappedColumnType特征中HasDatabaseConfigProvider特征的UsersComponent。 但是在UsersComponent初始化驱动程序尚未注入的那一刻,这会导致NPE。 您可以将roleMapper val lazyval更改为def

implicit lazy val roleMapper = ...

OR

implicit def roleMapper = ...

答案 1 :(得分:0)

你选择- (NSFetchedResultsController *)fetchedResultsController { NSManagedObjectContext *managedObjectContext = [self managedObjectContext]; if (_fetchedResultsController != nil) { return _fetchedResultsController; } NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"Favourites" inManagedObjectContext:managedObjectContext]; fetchRequest.entity = entity; NSPredicate *d = [NSPredicate predicateWithFormat:@"title != nil"]; [fetchRequest setPredicate:d]; NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:NO]; fetchRequest.sortDescriptors = [NSArray arrayWithObject:sort]; fetchRequest.fetchBatchSize = 20; NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil]; self.fetchedResultsController = theFetchedResultsController; _fetchedResultsController.delegate = self; return _fetchedResultsController; } 的任何特殊原因?如果是的话,我无法帮助你,但我可以建议使用密封的特征+案例对象+ sealerate

Enumeration创建随播广告并描述case class User

Role

object User { sealed trait Role case object None extends Role case object Root extends Role case object Admin extends Role // A bit messy stuff to convert Role to String and back def s = sealerate.values[Role].foldLeft(Map[String, Role]()) { case (m, f) ⇒ m.updated(f.toString, f) } implicit val roleColumnType: JdbcType[Role] with BaseTypedType[Role] = MappedColumnType.base[Role, String](_.toString, s) } 添加到role案例类

User

case class User( uid: Option[Long] = None, role: Option[User.Role] = User.None, firstName: String, lastName: String, middleName: Option[String] = None, email: String, avatarUrl: Option[String], created: DateTime = DateTime.now, modified: DateTime = DateTime.now ) 添加到role表格

Users

全部:)

Scala枚举here的简要说明。