mysql - 使用 Slick (Scala) 将记录插入数据库,实体的最佳实践

标签 mysql database scala slick

首先要说的是,我是 Scala 的新手,确实需要一点帮助。我需要构建一个 Web api,并且我将尝试将一条记录插入数据库,但在将实体(数据库表)映射到模型(类)时遇到一些问题。我使用.Net Core Web API(在那里我使用Entity Framework Core,这里在Scala使用Slick)并尝试在Scala中保持相同的架构,但需要更多信息,因为在互联网上我找到了很多版本,并且可以不选择最好的。 数据库采用MySQL。

User.scala

        case class User(
                     id: Int = 0,
                     userName: String,
                     firstName: String,
                     lastName: String
                   ) {
      override def equals(that: Any): Boolean = true
    }

    object User {    
      implicit object UserFormat extends Format[User] {
        def writes(user: User): JsValue = {
          val userSeq = Seq(
            "id" -> JsNumber(user.id),
            "userName" -> JsString(user.userName),
            "firstName" -> JsString(user.firstName),
            "lastName" -> JsString(user.lastName)
          )
          JsObject(userSeq)
        }

        def reads(json: JsValue): JsResult[User] = {    
          JsSuccess(User(
            (json \ "id").as[Int].value,
            (json \ "userName").as[String].value,
            (json \ "firstName").as[String].value,
            (json \ "lastName").as[String].value)
          )
        }
      }

      def tupled = (this.apply _).tupled
    }

class UserMap @Inject()(protected val dbConfigProvider: DatabaseConfigProvider)(implicit ex: ExecutionContext) {
  val dbConfig: DatabaseConfig[JdbcProfile] = dbConfigProvider.get[JdbcProfile]
  val db: JdbcBackend#DatabaseDef = dbConfig.db
  val dbUsers = TableQuery[UserDef]

  def getAll(): Unit = {
    val action = sql"SELECT Id, UserName, FirstName, LastName FROM Users".as[(Int, String, String, String)]
    return db.run(action)
  }

  def add(user: User): Future[Seq[User]] = {
    dbUsers += user
    db.run(dbUsers.result)
  }
}

UserDef.scala(这是数据库表/实体的映射器)

  class UserDef(tag: Tag) extends Table[User](tag, "Users") {
  def id = column[Int]("Id", O.PrimaryKey, O.AutoInc)
  def userName = column[String]("UserName")
  def firstName = column[String]("FirstName")
  def lastName = column[String]("LastName")

  override def * = (id, userName, firstName, lastName) <> (create, extract)

  def create(user: (Int, String, String, String)): User = User(user._1, user._2, user._3, user._4)
  def extract(user: User): Option[(Int, String, String, String)] = Some((user.id, user.userName,user.firstName,user.lastName))
}

UsersController.scala

    def createUser = Action(parse.json) { implicit request => {
    val userJson = request.body

    var user = new User(
      -1,
      (userJson \ "userName").as[String].value,
      (userJson \ "firstName").as[String].value,
      (userJson \ "lastName").as[String].value
    )

    var users = TableQuery[UserDef]
    Await.result(db.run(DBIO.seq(
      users += user,
      users.result.map(println))), Duration.Inf
    )

    Ok(Json.toJson(user))
  }
  }

我如何看待这个问题:

  • UserDef 是一个实体,必须保持干净,只有表列定义

  • UserMap是User类和UserDef(实体)之间的桥梁,可以用作具有增删改查方法的存储库(getAll()、getById(id)、create(user)、update(user)、delete( ID))。它与 User 类位于同一文件中,但可能必须移至另一个文件中。

  • 用户类是模型,只需要包含其参数和写入/读取(Scala 细节)

现在在 Controller 中:

如果我尝试使用当前方法将记录插入数据库,首先我需要从表中获取所有行,然后将新记录添加到列表中。如果此表中有 3 400 万条记录,会发生什么情况?仅插入新行将使所有这些行变得无用。

然后,插入这个新行后,我需要将其返回到客户端,但是如何更新它(Id 每次都是 -1,但是如果我获取整个列表以查看它包含的内容,我可以看到最新实体的正确 ID)

谢谢

最佳答案

最后,我找到了一个很好的解决方案并将其发布在这里,也许有人需要这个:

UserMap,对我来说至少会变成UserRepository。在那里我有 CRUD 操作,也许还有一些额外的操作:

  def getAll(): Future[Seq[User]] = {
    db.run(dbUsers.result)
  }

  def getById(id: Int): Future[Option[User]] ={
    val action = dbUsers.filter(_.id === id).result.headOption
    db.run(action)
  }

  def create(user: User): Future[User] = {
    val insertQuery = dbUsers returning dbUsers.map(_.id) into ((x, id) => x.copy(id = id))
    val action = insertQuery += user
    db.run(action)
  }

  def update(user: User) {
    Try( dbUsers.filter(_.id === user.id).update(user)) match {
      case Success(response) => db.run(response)
      case Failure(_) => println("An error occurred!")
    }
  }

  def delete(id: Int) {
    Try( dbUsers.filter(_.id === id).delete) match {
      case Success(response) => db.run(response)
      case Failure(_) => println("An error occurred!")
    }
  }

和UsersController:

  def getAll() = Action {
    var users = Await.result(usersRepository.getAll(), Duration.Inf)
    Ok(Json.toJson(users))
  }

  def getById(id: Int) = Action { implicit request => {
    val user = Await.result(usersRepository.getById(id), Duration.Inf)

    Ok(Json.toJson(user))
    }
  }

  def create = Action(parse.json) { implicit request => {
    val userJson = request.body

    var user = new User(
      -1,
      (userJson \ "userName").as[String].value,
      (userJson \ "firstName").as[String].value,
      (userJson \ "lastName").as[String].value
    )
    var createdUser = Await.result(usersRepository.create((user)), Duration.Inf)
    Ok(Json.toJson(createdUser))
    }
  }

  def update(id: Int) = Action(parse.json) { implicit request => {
    val userJson = request.body

    var user = new User(
      (userJson \ "id").as[Int].value,
      (userJson \ "userName").as[String].value,
      (userJson \ "firstName").as[String].value,
      (userJson \ "lastName").as[String].value
    )

    var updatedUser = usersRepository.update(user)
    Ok(Json.toJson(user))
    }
  }

  def delete(id: Int) = Action {
    usersRepository.delete(id)
    Ok("true")
  }

无论如何,我知道我有一些坏代码块......特别是在创建和更新方法中,其中将 json 转换为用户。

关于mysql - 使用 Slick (Scala) 将记录插入数据库,实体的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58078351/

相关文章:

mysql - 选择未按预期工作时的情况

mysql 将一项 id 设置为 auto_increment max id

java - 如何使用java JDBC获取MySql的数据库列表 "Schema"名称

scala - 无法将元素添加到 Play session

scala - 值查找解析为 sbt 插件中的错误范围

mysql - 在 VS 2017 中添加 ADO.NET 实体数据模型并且没有任何反应

mysql - 尝试将 varchar 转换为 decimal 时的奇怪行为

java - 什么可以使此 dsl 更易于键入或阅读?

MySQL:给定一行和多个字符串。查找包含在行中的字符串

scala - 如何在 Scala 中定义包私有(private) *trait*?