首先要说的是,我是 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/