上一节我们简单介绍了数据库的读写,所使用的数据库都是随便写的(用水果代替,但不是真正的食品零售数据表,至少没有价格,销量等等)。这一节我们思考如何实现一个测试题的数据库,所谓的测试题数据库就是假定系统里预存了1000道题目,每个学生考试随机抽查50题,以保证每次考试很难相互抄袭,而且每个题目设置时间限制,到时间不作答就认为放弃,考试完成自动阅卷等等,这些功能都是普通的纸质考试没法实现的。

 

那么首先就是数据库的设计,能够想到的试题至少包含下面的信息(题目的参考答案和当前答案是一个很难讲的问题,比如选择题有多选的情况,比如简答题没法一一对应的情况,但是为了简化起见还是应该先做成字符串,如果用户回答A,B,C三个而正确答案是AB两个,则错选0分,如果正确答案是ABCD,则漏选得一半分数,这些复杂的逻辑处理要后面慢慢优化,一开始要先把大的框架搭建好)

初步设计成两张表,一个是试题库,一个是考试记录库(可能我们需要统计有多少人参加了考试,考试的结果,每个学生的成绩之类的,表的结构不合理后面可以再修改,基本的功能应该够了)

 

有了数据库之后,下面一步就是录入试题(对应了数据库的增加),可以想象淘宝网如果没有卖家先把宝贝传到数据库,买家搜不到任何东西,这个网站也没有任何价值,所以数据库首先要有内容,我们要首先设计一个人机界面,给老师录入试题。注意要尽量用最适合的控件,比如编号就是数字上下的控件,试题类型就是combobox,而文本框也要做一些限制,比如只允许输入数字(可以提高软件的用户体验)

 

把数据库的连接做成一个标准方法,例如我们可以指定在连接的时候需要给目标数据库的路径,密码,数据表的名称(其实还可以做得更复杂,比如不带密码则密码设置为空,当检测到密码为空的时候就用不带密码的语句),注意把原来字符串替换成变量的写法,选出来之后替换成两个双引号,然后再在中间加两个空格,再在空格中加变量名,这样不容易出错,连接成功或者失败也是布尔值对外返回。

 

为了让代码更加整洁,对一个题目所包含的全部信息,我们都做成一个结构体(这个结构体要跟数据库对应起来),这个数据库增加方法就比较简洁,只需要传入一个自定义类型即可

 

在点击录入按钮的时候,首先实例化一个结构体,然后执行具体函数,为了测试方便可以随便录入几个数据(我们可以从数据库更精简的角度出发,如果问题类型保存原模原样的字符串"判断题","选择题","简答题",那么同样的一条记录会耗费更多的存储空间,所以在真正的数据库设计中都需要把每个字段设计的尽可能简洁)

 

把数据录入的方法也做成函数的方式,注意传入的是一个结构体类型(这个结构体就对应一条记录,以后一种数据库文件的读写对应一种结构体,也对应一种方法这样做比较好移植和修改)

 

数据录入其实首先要执行一个数据查询,比如你淘宝注册一个账号,上传一个宝贝,肯定有很多规则限制。账号的用户名不允许非法字符,宝贝的描述不允许有敏感字符等等。我们这里因为只是自己用,所以可以暂时不考虑这些,但是试题编号肯定要求唯一,不然就有缺陷了,没法真正排序得到从小到大的结果了(我们可能还想着1-100题都是判断题,101-200题都是选择题,出题的时候从1-100和101-200都随机出20题这样)

 

有了数据库内容的录入,就需要考虑修改和删除(当然你直接打开数据库像操作Excel一样也是一种方法,但是不推荐这么做),在做页面之前需要注意,我们用了一个tabcontrol来更好的管理整个程序布局,在代码上也要划区域,不要搞得很乱,所有跟试题录入相关的方法都放在一起,并用一个region括起来(跟全局的也要分开)

 

整个试题查看的界面设计如下,为了方便快速查看试题,还需要做上一题/下一题的按钮(或者像很多网页一样显示1-10条,11-20条这种十个记录一次显示,我们都会在下面讲到,在试题查看的时候我们把试题的ID也显示出来了,而在试题录入的时候是没有的,因为只有执行完毕才会生成一个唯一的ID,这里试题查看/修改/删除都是根据这个唯一的ID来的,而不是编号)

 

在切换到试题查看页面的时候,我们需要遍历数据库得到所有的记录,然后放到comboBox给用户随时选择切换试题(这里写了一个DataBaseQuestionGetALL的方法,就是对数据库的所有记录根据某个字段升序或者降序提取出来,参考前面一章直接把ACCESS读取并放到DataGridView显示的功能,这里我们也用到了类似的功能)

 

这里我们做了一个List可变数组,把所有记录放在List中,但是其实这样做在真实的项目中还是会有问题,比如一个淘宝商品有太多属性,商品描述包含的图片,文字信息有几千个字符,你一条记录就很大,几十万条几百万条记录要统统存到一个List里面你程序就卡死了(而实际上我们目的只是要方便用户快速选择试题,所以只列举跟当前试题编号接近的10个题目就行了)

 

所以就有了"上一题","下一题"的功能需求。比如我要选择试题编号比当前NO大的三条,并且从小到大排序,或者要选择比当前NO小的一条,就可以使用较为复杂的Select语句,你需要 Top X * 并且添加order by XXX, asc或者desc分别表示升序和降序(第一依据是Question_NO的升序,第二依据是ID的升序,因为第一依据不是主键,可能会有重复的Question_NO,或者按试题分数,限制时间排序都不一定是唯一的,如果不唯一这个select语句就可能不按照你的提示选出来指定的记录数,所以最后要再跟一个唯一的主键ID的排序)

 

修改此题也比较好理解了,注意跟前面一样,传入的是一个结构体类型,修改成功或者失败都有返回值

 

删除也比较好理解,只不过删除了这一题,为了提高用户体验,还需要直接刷新到下一题(如果真的要做优化还是有很多判断没有做,比如当前就是最后一题,那么就跳到上一题或者第一题,删除之前弹出个确认框之类的)

 

 

更多教学视频和资料下载,欢迎关注以下信息:

我的优酷空间:

http://i.youku.com/acetaohai123

 

我的在线论坛:

http://csrobot.gz01.bdysite.com/

 

问题交流:

QQ:910358960

邮箱:acetaohai123@163.com

 

 

 

 

 

C#基础视频教程6.2 如何简单读写数据库的更多相关文章

  1. C#基础视频教程6.1 如何简单读写数据库

    要理解MySQL,SQLServer,ACCESS都是数据库的品牌,不同品牌的数据库在不同的领域,适用场合有所不同.ACCESS应该是最简单,至少是Windows上最容易上手的数据库,MySQL可能跟 ...

  2. C#基础视频教程6.3 如何简单读写数据库

    在继续往下做之前,我们需要把之前的代码尽可能的精简(会对后面很有好处,而且读者也应该仔细比对这一部分的代码和上一部分哪里真正得到了优化,从而提高编程水平). 首先数据库的操作类有哪些是可以做的更加普遍 ...

  3. C#基础视频教程5.3 如何编写简单的超级热键

    跟前面一章讲解计算器一样,到最后一小节,我们总是要把代码规整好,让整个程序显得非常简洁,先做个文件夹把我们自定义的类库都放进去   然后我们开始整理Form1里面的代码,为了实现超级热键的功能,我们应 ...

  4. JavaScript基础视频教程总结(131-140章)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  5. JavaScript基础视频教程总结(081-090章)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  6. JavaScript基础视频教程总结(001-010章)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  7. JavaScript基础视频教程总结(011-020章)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  8. Java入门到精通——基础篇之多线程实现简单的PV操作的进程同步

    Java入门到精通——基础篇之多线程实现简单的PV操作的进程同步 一.概述     PV操作是对信号量进行的操作.     进程同步是指在并发进程之间存在一种制约关系,一个进程的执行依赖另一个进程的消 ...

  9. python3基础视频教程

    随着目前Python行业的薪资水平越来越高,很多人想加入该行业拿高薪.有没有想通过视频教程入门的同学们?这份Python教程全集等你来学习啦! python3基础视频教程:http://pan.bai ...

随机推荐

  1. HDU 6052 To my boyfriend(概率 贡献)

    To my boyfriend Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  2. cloudstack ssvm 管理地址不够造成无法启动修复过程

    cloudstack日志记录: 上面已经提示了,管理ip没有了,造成这个原因很多,遇到过ssvm非正常关闭就有可能不释放IP慢慢把IP消耗掉.总之这肯定是BUG.按照上面的提示找到对应pod 和dc ...

  3. FastReport.Net使用:[20]条码控件使用

    在日常生活中,条码用的越来越多,“扫一扫”目前是非常的流行.报表设计也要跟上时代,打印出条码,方便信息流转. FastReport对条码的支持很不错,支持很多类型的条码,还包括二维码. 几个常见问题 ...

  4. [HEOI2013]SAO

    题目大意: 一个有向无环图上有n个结点, 现在告诉你n-1个条件(x,y),表示x和y的先后关系. 问原图共有几种可能的拓扑序? 思路: 树形DP. f[i][j]表示对于第i个结点,有j个点在它前面 ...

  5. Eclipse下使用Stanford CoreNLP的方法

    源码下载地址:CoreNLP官网. 目前release的CoreNLP version 3.5.0版本仅支持java-1.8及以上版本,因此有时需要为Eclipse添加jdk-1.8配置,配置方法如下 ...

  6. 对Java Serializable(序列化)的理解和总结(一)

    导读:最近在做项目的过程中,发现一个问题,就是我们最开始的时候,传递参数包括返回类型,都有map类型.但是由于map每次都要匹配key值,很麻烦.所以在之后就将参数传递和返回类型全都改成了实体bean ...

  7. 【洛谷】P1176: 路径计数2【递推】

    P1176 路径计数2 题目描述 一个N×N的网格,你一开始在(1,1),即左上角.每次只能移动到下方相邻的格子或者右方相邻的格子,问到达(N,N),即右下角有多少种方法. 但是这个问题太简单了,所以 ...

  8. bzoj 1101

    其实这个用的是Mobius反演的第二种形式 F(d) = (n div d) * (m div d) f(d) = [ gcd(i,j)=d ] (i in [1,a], j in [1,b]) /* ...

  9. Unity随手机

    该文章持续更新! 协程的返回值必需是 IEnumerator 协程的参数不能加关键字 ref 或 out 在函数 Update 和 FixedUpdate 中不能使用 yield 语句,但可以启动协程 ...

  10. POJ 2774 Long Long Message 后缀数组模板题

    题意 给定字符串A.B,求其最长公共子串 后缀数组模板题,求出height数组,判断sa[i]与sa[i-1]是否分属字符串A.B,统计答案即可. #include <cstdio> #i ...