【发布时间】:2019-09-24 10:35:30
【问题描述】:
首先要说,我是 Scala 的新手,真的需要一点帮助。我需要构建一个 web api,我会尝试将一条记录插入数据库,但是在将实体(db 表)映射到模型(类)时遇到了一些问题。我使用 .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(这是一个db表/实体的映射器)
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(实体)之间的桥梁,可以用作带有 crud 方法(getAll()、getById(id)、create(user)、update(user)、delete( ID))。这与 User 类在同一个文件中,但可能必须移到另一个文件中。
用户类是模型,只需要包含它们的参数和写入/读取(Scala 特性)
现在在控制器中:
如果我尝试使用当前方法将记录插入数据库,首先我需要从表中获取所有行,然后将新记录添加到列表中。如果我在这个表中有 3 400 万条记录会发生什么?将让所有这些行无用,只插入一个新行。
然后,在插入这个新行之后,我需要将它返回给客户端,但是我如何才能更新它(ID 每次都是 -1,但是如果我得到整个列表来查看它包含的内容,我可以看到最新实体的正确 ID)
谢谢
【问题讨论】:
-
为什么需要从表中获取所有行来插入新记录?
users += user只进行插入,不获取任何行。 -
要获取插入的行id,可以在insert上使用
returning子句,见stackoverflow.com/a/31448129/14955 -
UserMap是个好东西。为什么你的控制器中有db.run代码而不是在UserMap中调用add方法?为什么add返回一个Seq[User]而不仅仅是新添加的单个User或其新ID?
标签: mysql database scala slick