【发布时间】:2023-02-06 20:28:37
【问题描述】:
我正在构建一个费用跟踪器应用程序,使用 Spring Boot 和 Kotlin 来制作 API,并将用户数据存储到 Postgresql 数据库中。我选择了 Exposed ORM 来处理 Spring 和 Postgres 之间的所有 CRUD 操作。
要将费用插入数据库,用户可以选择标签以更好地组织他们的费用。费用和标签是多对多关系(一个费用可以有多个标签,一个标签可以有多个费用)。
我有以下代码来定义表:
费用
object ExpenseTable : IntIdTable("expense") {
val userId: Column<String> = varchar("user_id", 50)
val concept: Column<String> = varchar("concept", 50)
val total: Column<Double> = double("total")
val dateAdded: Column<LocalDateTime> = datetime("date_added")
val comments: Column<String?> = varchar("comments", 200).nullable()
}
class ExpenseEntity(
id: EntityID<Int>
) : IntEntity(id) {
companion object : IntEntityClass<ExpenseEntity>(ExpenseTable)
var userId by ExpenseTable.userId
var concept by ExpenseTable.concept
var total by ExpenseTable.total
var dateAdded by ExpenseTable.dateAdded
var tags by TagEntity via ExpensesTags
var comments by ExpenseTable.comments
fun toExpense() = Expenses(
id.value,
userId,
concept,
total,
dateAdded,
tags.toList().toTags(),
comments
)
}
标签
object TagsTable: IntIdTable("tag") {
val tagName: Column<String> = varchar("tag_name", 25)
val dateAdded: Column<LocalDateTime> = datetime("date_added")
}
class TagEntity(
id: EntityID<Int>
): IntEntity(id) {
companion object: IntEntityClass<TagEntity>(TagsTable)
var tagName by TagsTable.tagName
var dateAdded by TagsTable.dateAdded
fun toTags() = Tags(
id.value,
tagName,
dateAdded
)
}
多对多关系
object ExpensesTags : Table() {
val expense = reference("expense", ExpenseTable)
val tag = reference("tag", TagsTable)
override val primaryKey = PrimaryKey(expense, tag, name = "PK_ExpensesTags")
}
我只想拥有一种用户可以创建的标签,到目前为止的问题是,使用 ORM 中的可用代码,我无法找到一种方法来确保用户正在使用的标签是否存在。
到目前为止,我已经有了这个实现,但我觉得这不是最好的方法,因为我需要查询并检查标签是否已经存在,而且感觉有点过头了。
fun insertExpense(expenses: ExpensesPost): Expenses {
val userIdName = authenticationFacade.userId()
val tagsPost = expenses.tag
// We only accept 10 tags max per request
if (tagsPost.size > MAX_TAG_REQUEST) throw BadRequestException(
Status.BAD_REQUEST,
"Only $MAX_TAG_REQUEST tags are allowed"
)
var insertedExpense: Expenses? = null
loggedTransaction {
// Check if some tags already exists
tagsPost.forEach { tag ->
val internTag = tagsCrudTable.find { TagsTable.tagName eq tag.tagName }.firstOrNull()
// Only insert into the table tags that doesn't exist
if (internTag == null) {
tagsCrudTable.new {
dateAdded = tag.dateAdded
tagName = tag.tagName
}
}
}
// Get all the tags that come from the request
val tagsArr = mutableListOf<TagEntity>()
tagsPost.map {
val internTag = tagsCrudTable.find {
TagsTable.tagName eq it.tagName
}.first()
tagsArr.add(internTag)
}
val expense = expenseCrudTable.new {
userId = userIdName
concept = expenses.concept
total = expenses.total
dateAdded = expenses.dateAdded
comments = expenses.comments
}
expense.tags = SizedCollection(tagsArr)
insertedExpense = expense.toExpense()
}
return insertedExpense ?: throw EntityNotFoundException(
status = Status.NO_DATA,
customMessage = "Something went wrong",
id = authenticationFacade.userId()
)
}
【问题讨论】:
标签: postgresql spring-boot kotlin orm kotlin-exposed