vok-orm 关联性资料的新增/查询 (上篇) -- d08

本节重点

  • 延续先前己建立的学生资料范例,今天加上学生成绩。

    1. 建立成绩资料
    2. 在显示单笔学生资料页StudentView.kt上加上新增及显示成绩画面
    3. Refactor 时加入 VoK karibu-dsl 套件特色 (下篇)
  • vok-orm和许多orm使用方式类似,在这篇文里不会特别详细解说,倘若未曾使用过任何jpa、orm,看这篇文章时可先忽略雾里看花的部份,日後会专篇介绍。

第二个资料表

  • 新增学生成绩 entify,开新档 Grade.kt
data class Grade(
    override var id: Long? = null,
    var student_id: Long? = null,
    val description: String? = null,
    var english: Double? = null,
    var math: Double? = null,
    var mandarin:Double? = null,
    var pe: Double? = null
): KEntity<Long>{
    companion object: Dao<Grade, Long>(Grade::class.java)
    val student: Student?
        get() = student_id?.let { Student.getById(student_id!!)} ?: null
}
  • 建立资料表 Grade,请开新档 V02__CreateGrade.sql (命名规格请参考d04)
create TABLE Grade(
    id bigint auto_increment PRIMARY KEY,
    mandarin DOUBLE NOT NULL,
    description VARCHAR(50) NOT NULL,
    english DOUBLE NOT NULL,
    math DOUBLE NOT NULL,
    pe DOUBLE NOT NULL,
    student_id bigint not null REFERENCES Student(id)
)

在这张资料表里除了自动编号的 primary key id外,还有一个 foreign key student_id,由於使用 H2 database,所以程序重启时,两个.sql都会执行。倘若使用的是其他资料库如 MySQL,则 FlyWay 只会执行尚未被执行的.sql。

  • 接着在显示学生资料画面上加上编辑画面,请打开StudentView.kt
        :
        : 

    private lateinit var student: Student
    private lateinit var gradeDiv: Div
    private val gradeBinder = beanValidationBinder<Grade>()
    private lateinit var addGradeButton: Button
    private val root = ui {
        verticalLayout {
        :
        :
        :
            h2("成绩")
            gradeDiv = div()
            p("新增成绩")

            textField("学期"){
                bind(gradeBinder).bind(Grade::description)
                placeholder = "第一学期"
            }
            numberField("国文"){
                bind(gradeBinder).bind(Grade::mandarin)
            }
            numberField("英文"){
                bind(gradeBinder).bind(Grade::english)
            }
            numberField("数学"){
                bind(gradeBinder).bind(Grade::math)
            }
            numberField("体育"){
                bind(gradeBinder).bind(Grade::pe)
            }
            addGradeButton = button("新增"){
                onLeftClick { addGrade() }
            }
            editLink = routerLink(VaadinIcon.EDIT,null)
        }
    }

gradeDiv = div() 表示在画面上新增空的DIV区块

  • 验证储存
    private fun addGrade() {
        val grade = Grade()
        if (gradeBinder.validate().isOk && gradeBinder.writeBeanIfValid(grade)){
            grade.student_id = student.id
            grade.save()
            refreshGrades()
            gradeBinder.readBean(Grade())
        }
    }
  • 新增成功後更新画面
    private fun refreshGrades() {
        gradeDiv.removeAll()
        student.grades.fetch().forEach {
            gradeDiv.html("<p>" +
                    "<strong>学期:</strong>${it.description} " +
                    "<strong>国文:</strong>${it.mandarin} " +
                    "<strong>英文:</strong>${it.english} " +
                    "<strong>数学:</strong>${it.math} " +
                    "<strong>体育:</strong>${it.pe}" +
                    "</p>")
        }
    }

清空DIV区块,查询这位学生所有成绩後再逐一显示,这里插入div区块使用的是html,在VoK里,对dom的操作也极为容易。

  • 在 data class Student 加上grads属性。请打开Student.kt
    val grades : DataLoader<Grade>
        get() = Grade.dataLoader.withFilter {
            Grade::student_id eq id
        }

当有人读取grads时,下条件查询资料来源 Grade

  • 最後,记得要在Grade.kt加上栏位验证资讯
    @field:NotNull
    var student_id: Long? = null,

    @field:NotNull
    @field:Size(min = 4)
    var description: String? = null,

    @field:NotNull
    @field:DecimalMin(value = "0.0")
    @field:DecimalMax(value = "100.0")
    var english: Double? = null,
    
    :
    :
    (略)

执行结果 :

https://ithelp.ithome.com.tw/upload/images/20210923/20138680MdrMDOMbpp.png

本日Source Code已上传 GitHub


<<:  D8 - 彭彭的课程#Python 集合、字典的基本运算 - Set、Dictionary

>>:  Day 22 - Ajax

Day 03-选择Node.js&Express

Node.js: 是一种用JavaScript撰写的环境,以及内建处理网路请求和函式库。 为什麽选择...

[Day 28] PHP array_column / array_keys / array_values

假设目前有阵列 $fruits = [ ['id'=>0,'fruit'=>'apple...

Azure - Day4 Cosmos DB

Hi~大家好,我今天想要分享的实作包括如下: < Cosmos DB > 1. 如何建立...

[Day 24 - Modern CSS] 在JS中写CSS,神套件Styled-components

要如何在 React 中撰写 CSS,为元素添加样式?目前的方法有 Inline-Style、CSS...

到底是什麽意思?Typescript Partial<Type>

今天在翻旧code的时候,看到了 Partial 的写法,所幸来查查这到底是什麽意思.弄懂了之後看c...