背景概要
在.NET Core 刚刚1.0 RC的时候,我就给OData团队创建过Issue让他们支持ASP.NET Core,然而没有任何有意义的答复。
Roadmap for ASP.NET Core 1.0 RC2?
接着,在.NET Core 1.0刚刚发布的时候,又给他们创建了另外一个Issue,虽然被他们列为P1,但是已经没有下文:
Roadmap for OData WebAPI run on ASP.NET Core 1.0
然后在.NET Core 2.0 Preview版本发布的时候,我继续给OData 团队提Issue:
[vNext] Even ASP.NET Core 2 Preview 1 announced, OData WebAPI vNext still no updates
最终,在OData 7.0的时候,OData发布了基于ASP.NET Core的支持。
经过这么长时间的测试和迭代,我想,是时候创建一个基于OData的Web API。
不幸的是,OData再次走在ASP.NET Core 后面: Issue,所以这个例子只能使用ASP.NET Core 2.2。
所幸的是,自从7.3.0-beta开始支持.NETCore 3.0(更新日期:2019.12.11),后续的博客中使用了该Beta版本以及更高版本。
更新于2020.07.01:使用了OData WebAPI 7.4.1。
更新于2020.12.17:使用了OData WebAPI 7.5.2。
业务场景 Business Scenario
自孩提起,我们就听到这个传承至今的谚语:
活到老学到老!
学习,变成了我们人生的一份,也变成了一种生活态度。那么,有了态度,加上点办法就能让学习的过程更加顺畅和有动力。
所以,从业务场景来看,或者直接了当地从我们学习的过程来看,以下功能点是必须的:
- 学习笔记。分门别类、结构化的学习笔记系统;
- 练习题库。没有练习的学习,是不可能有效果的;
- 错题记录(对应的实现并未包含在这个Blog系列里面,因为这个牵扯到)。只做题不纠正只会重复犯错。
- 练习题参考答案。没有答案的练习题是不完整的。
Knowledge Builder,就是符合上述业务场景的。它是一个用来创建、维护、浏览、测试和巩固知识点(Knowledge Items)的Web App。而Knowledge Builder API是服务于其需求的API。
它包含这么几种类型的对象:
- Knowledge Item。知识点。
- Exercise Item。题库项。
Knowledge Item 知识点
Item Category 知识点类型
知识点是有类型的。简单易懂的来说,就常见的语数英。
再细致一点,语数英也是分年级的。高等数学与初等属性的知识点的深度可能完全不同。
Item Content 知识点内容
从内容上看,Knowledge Item本身要支持各种特殊符号,而且需要支付各种数学公式、数学图形等。
Knowledge Item还需要支持音频和视频格式,来应对更广泛的学科。
所以,Markdown格式不失为当下不错的选择。
Exercise Item 题库项
题库项是可以基于Knowledge Item,但是也可以跟Knowledge Item没有关联。
题库项的类型:
- 问答题
- 选择题 (题干和选择项目)
- 阅读理解(使用层次结构达到)
存储层设计 Database table design
Knowledge Item 知识点
从存储层的维度来看,Knowlege Item核心部分是个复杂文本,外加一些额外的属性。
为了简单起见,这个系列的Blog中不涉及Category,并且Content Type也仅仅作为个占位符。
数据库表定义如下(基于T-SQL):
CREATE TABLE [KnowledgeItem] (
[ID] INT IDENTITY (1, 1) NOT NULL,
[ContentType] SMALLINT NULL,
[Title] NVARCHAR (50) NOT NULL,
[Content] NVARCHAR (MAX) NOT NULL,
[Tags] NCHAR (100) NULL,
[CreatedAt] DATETIME DEFAULT (getdate()) NULL,
[ModifiedAt] DATETIME DEFAULT (getdate()) NULL,
PRIMARY KEY CLUSTERED ([ID] ASC)
);
Exercise Item 题库项
题库项的类型:
- 问答题
- 选择题 (题干和选择项目)
- 阅读理解(使用层次结构达到)
数据库表定义如下(基于T-SQL):
CREATE TABLE [ExerciseItem] (
[ID] INT IDENTITY (1, 1) NOT NULL,
[KnowledgeItem] INT NULL,
[ExerciseType] SMALLINT NOT NULL,
[Content] NVARCHAR (MAX) NOT NULL,
[CreatedAt] DATETIME DEFAULT (getdate()) NULL,
[ModifiedAt] DATETIME DEFAULT (getdate()) NULL,
PRIMARY KEY CLUSTERED ([ID] ASC),
CONSTRAINT [FK_EXECITEM_KITEM] FOREIGN KEY ([KnowledgeItem]) REFERENCES KnowledgeItem ([ID]) ON DELETE SET NULL
);
CREATE TABLE [ExerciseItemAnswer] (
[ItemID] INT NOT NULL,
[Content] NVARCHAR (MAX) NOT NULL,
[CreatedAt] DATETIME DEFAULT (getdate()) NULL,
[ModifiedAt] DATETIME DEFAULT (getdate()) NULL,
PRIMARY KEY ([ItemID] ASC),
CONSTRAINT [FK_EXECAWR_EXECITEM] FOREIGN KEY ([ItemID]) REFERENCES ExerciseItem ([ID]) ON DELETE CASCADE ON UPDATE CASCADE
);
下一篇介绍如何设置Project:Part II: Project setup
项目Repo: https://github.com/alvachien/knowledgebuilderapi
是为之记。
Alva Chien
2019.11.03
Updated on 2020.07.01
Updated on 2020.12.17
Updated on 2020.12.20: remove ParentID, Update ExerciseType;