I have 2 entities – a Question and a TestPaper. The mapping between both should be many to many given that a test paper can have many questions and a question can belong in many test papers.
`@Serdeable
@MappedEntity
data class Question(
@Id @GeneratedValue(Type.AUTO) val id: Long? = null,
var department: String,
var courseId: Long,
var questionText: String,
var questionType: String,
var mediaUri: String?,
@Relation(value = MANY_TO_MANY, cascade = [ALL])
@JoinTable(
name = "test_paper_question",
joinColumns = [JoinColumn(name = "question_id")],
inverseJoinColumns = [JoinColumn(name = "test_paper_id")]
)
@JsonIgnore
var testPapers: MutableList<TestPaper> = mutableListOf()
)`
@Serdeable @MappedEntity data class TestPaper( @Id @GeneratedValue(GeneratedValue.Type.AUTO) val id: Long? = null, var department: String, var courseId: Long, @Relation(value = MANY_TO_MANY, mappedBy = "testPapers") var questions: MutableList<Question> = mutableListOf() )
This how I add a question to a test paper and also retrieve it
`@Singleton
open class TestPaperService(
private val testPaperRepository: TestPaperRepository,
private val questionRepository: QuestionRepository
) {
@Transactional
open fun addQuestionToTestPaper(testPaperId: Long, questionId: Long): TestPaper {
val testPaper = testPaperRepository.findById(testPaperId).orElseThrow {
RuntimeException(“TestPaper not found with id: $testPaperId”)
}
val question = questionRepository.findById(questionId).orElseThrow {
RuntimeException(“Question not found with id: $questionId”)
}
testPaper.questions.add(question)
question.testPapers.add(testPaper)
testPaperRepository.update(testPaper)
questionRepository.update(question)
return testPaper
}
@Transactional(readOnly = true)
open fun getQuestionsForTestPaper(testPaperId: Long): List<Question> {
val testPaper = testPaperRepository.findById(testPaperId).orElseThrow {
RuntimeException("TestPaper not found with id: $testPaperId")
}
return testPaper.questions
}
}`
I have written this test including print statements to see what the operations are doing –
@Test fun
test addQuestionToTestPaper adds a question successfully`() {
val question = Question(department = "Computer Science", courseId = 1, questionText = "What is calculus?", questionType = "Multiple Choice", mediaUri = null, testPapers = mutableListOf())
val savedQuestion = questionRepository.save(question)
val testPaper = TestPaper(department = "Computer Science", courseId = 1, questions = mutableListOf())
val savedTestPaper = testPaperRepository.save(testPaper)
val updatedTestPaper = testPaperService.addQuestionToTestPaper(savedTestPaper.id!!, savedQuestion.id!!)
val retrieved = testPaperService.getQuestionsForTestPaper(savedTestPaper.id!!)
val retrievedAfterUpdate = testPaperRepository.findById(3L)
println("saved: $savedTestPaper")
println("updated: $updatedTestPaper")
println("retrieved: $retrievedAfterUpdate")
assertTrue(retrieved.any { it.id == savedQuestion.id })
assertTrue(savedQuestion.testPapers.any { it.id == savedTestPaper.id })
}`
Here are the logs of the operations
01:04:24.142 [Test worker] DEBUG io.micronaut.data.query - Executing Query: SELECT test_paper_."id",test_paper_."department",test_paper_."course_id" FROM "test_paper" test_paper_ WHERE (test_paper_."id" = ?) 01:04:24.147 [Test worker] DEBUG io.micronaut.data.query - Executing Query: SELECT question_."id",question_."department",question_."course_id",question_."question_text",question_."question_type",question_."media_uri" FROM "question" question_ WHERE (question_."id" = ?) 01:04:24.150 [Test worker] DEBUG io.micronaut.data.query - Executing SQL query: UPDATE "test_paper" SET "department"=?,"course_id"=? WHERE ("id" = ?) 01:04:24.152 [Test worker] DEBUG io.micronaut.data.query - Executing SQL query: UPDATE "question" SET "department"=?,"course_id"=?,"question_text"=?,"question_type"=?,"media_uri"=? WHERE ("id" = ?) 01:04:24.158 [Test worker] DEBUG io.micronaut.data.query - Executing SQL query: UPDATE "test_paper" SET "department"=?,"course_id"=? WHERE ("id" = ?) 01:04:24.162 [Test worker] DEBUG io.micronaut.data.query - Executing SQL query: INSERT INTO "test_paper_question" ("question_id","test_paper_id") VALUES (?,?) 01:04:24.167 [Test worker] DEBUG io.micronaut.data.query - Executing Query: SELECT test_paper_."id",test_paper_."department",test_paper_."course_id" FROM "test_paper" test_paper_ WHERE (test_paper_."id" = ?) 01:04:24.168 [Test worker] DEBUG io.micronaut.data.query - Executing Query: SELECT test_paper_."id",test_paper_."department",test_paper_."course_id" FROM "test_paper" test_paper_ WHERE (test_paper_."id" = ?) saved: TestPaper(id=3, department='Computer Science', courseId=1, questions=0) updated: TestPaper(id=3, department='Computer Science', courseId=1, questions=1) retrieved: Optional[TestPaper(id=3, department='Computer Science', courseId=1, questions=0)] 01:04:24.175 [Test worker] DEBUG i.m.t.j.DataSourceTransactionManager - Rolling back JDBC transaction on Connection [HikariProxyConnection@193383192 wrapping org.testcontainers.jdbc.ConnectionWrapper@3bb9ca38] 01:04:24.176 [Test worker] DEBUG i.m.t.j.DataSourceTransactionManager - Setting JDBC Connection [HikariProxyConnection@193383192 wrapping org.testcontainers.jdbc.ConnectionWrapper@3bb9ca38] auto-commit [true]
I tried using JPA and now Micronaut’s own Data and JDBC (I know it is not an ORM and more of a data mapper) but I get the same results using both. I even tried to switch to a One to Many where a test paper can have many questions but I simply am not able to get questions to map to test papers.
Keshav Vel is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.