Anorm Scala 插入带有嵌套列表的对象列表
Anorm Scala insert list of objects with nested list
我发现自己需要将具有嵌套元素序列的元素序列插入到 PostgreSQL 数据库中,最好使用单个语句,因为我要返回 Future
。我正在使用 Scala Play 和 Anorm。
我的数据如下所示。
case class Question(id: Long, titel: String)
case class Answer(questionId: Long, text: String)
在数据库中它看起来像这样:
CREATE TABLE questions (
question_id SERIAL PRIMARY KEY NOT NULL,
titel TEXT NOT NULL,
);
CREATE TABLE answers (
answer_id SERIAL PRIMARY KEY NOT NULL,
question_id INT NOT NULL,
text TEXT NOT NULL,
FOREIGN KEY (question_id) REFERENCES questions(question_id) ON DELETE CASCADE
);
我的函数看起来像这样:
def saveFormQuestions(questions: Seq[Question], answers: Seq[Answer]): Future[Long] = {
Future {
db.withConnection{ implicit c =>
SQL(
// sql
).executeInsert()
}
}
}
不知何故,在 Anorm 中,SQL 或两者,我必须执行以下操作,最好是在单个事务中:
- foreach question in questions
- 将问题插入问题
- foreach answer in answers,其中answer.questionId == old question.id
- 使用从问题插入中获得的新问题 ID 将答案插入到答案中
我是 Scala Play 的新手,所以我可能做了一些不该做的假设。任何让我入门的想法都将不胜感激。
正如其名称所示,Anorm 不是 ORM,不会为您生成语句。
您必须确定适合表示数据和关系的语句(例如 my Acolyte tutorial)。
至于事务,Anorm 是 JDBC 的 thin/smart 包装器,因此 JDBC 事务语义是保留的。顺便说一句,Play 在其 DB
分辨率实用程序中提供了 .withTransaction
。
我用 db.withConnection 块中的逻辑解决了它。不知何故,我假设你必须在 db.withConnection 中有一个 SQL 语句,结果证明不是这样。所以像这样:
val idMap = scala.collection.mutable.Map[Long,Long]() // structure to hold map of old ids to new
db.withConnection { implicit conn =>
// save all questions and gather map of the new ids to the old
for (q <- questions) {
val id: Long = SQL("INSERT INTO questions (titel) VALUES ({titel})")
.on('titel -> q.titel)
.executeInsert(scalar[Long].single)
idMap(q.id) = id
}
// save answers with new question ids
if (answers.nonEmpty) {
for (a <- answers ) {
SQL("INSERT INTO answers (question_id, text) VALUES ({qid}, {text});")
.on('qid -> idMap(a.questionId), 'text -> a.text).execute()
}
}
}
我发现自己需要将具有嵌套元素序列的元素序列插入到 PostgreSQL 数据库中,最好使用单个语句,因为我要返回 Future
。我正在使用 Scala Play 和 Anorm。
我的数据如下所示。
case class Question(id: Long, titel: String)
case class Answer(questionId: Long, text: String)
在数据库中它看起来像这样:
CREATE TABLE questions (
question_id SERIAL PRIMARY KEY NOT NULL,
titel TEXT NOT NULL,
);
CREATE TABLE answers (
answer_id SERIAL PRIMARY KEY NOT NULL,
question_id INT NOT NULL,
text TEXT NOT NULL,
FOREIGN KEY (question_id) REFERENCES questions(question_id) ON DELETE CASCADE
);
我的函数看起来像这样:
def saveFormQuestions(questions: Seq[Question], answers: Seq[Answer]): Future[Long] = {
Future {
db.withConnection{ implicit c =>
SQL(
// sql
).executeInsert()
}
}
}
不知何故,在 Anorm 中,SQL 或两者,我必须执行以下操作,最好是在单个事务中:
- foreach question in questions
- 将问题插入问题
- foreach answer in answers,其中answer.questionId == old question.id
- 使用从问题插入中获得的新问题 ID 将答案插入到答案中
我是 Scala Play 的新手,所以我可能做了一些不该做的假设。任何让我入门的想法都将不胜感激。
正如其名称所示,Anorm 不是 ORM,不会为您生成语句。
您必须确定适合表示数据和关系的语句(例如 my Acolyte tutorial)。
至于事务,Anorm 是 JDBC 的 thin/smart 包装器,因此 JDBC 事务语义是保留的。顺便说一句,Play 在其 DB
分辨率实用程序中提供了 .withTransaction
。
我用 db.withConnection 块中的逻辑解决了它。不知何故,我假设你必须在 db.withConnection 中有一个 SQL 语句,结果证明不是这样。所以像这样:
val idMap = scala.collection.mutable.Map[Long,Long]() // structure to hold map of old ids to new
db.withConnection { implicit conn =>
// save all questions and gather map of the new ids to the old
for (q <- questions) {
val id: Long = SQL("INSERT INTO questions (titel) VALUES ({titel})")
.on('titel -> q.titel)
.executeInsert(scalar[Long].single)
idMap(q.id) = id
}
// save answers with new question ids
if (answers.nonEmpty) {
for (a <- answers ) {
SQL("INSERT INTO answers (question_id, text) VALUES ({qid}, {text});")
.on('qid -> idMap(a.questionId), 'text -> a.text).execute()
}
}
}