herose  
     
     
 

  基于.NET平台高考数据库的学生信息采集系统设计与实现

赵春江

摘 要 学籍管理是高等学校教学管理的一个重要组成部分.加强学籍管理,对于提高教学与教育质量有着十分重要的意义。本文分析了目前高校学籍管理中存在的问题,并提出了相应的对策。采用C/S架构实现录取信息数据库到SQL Server数据库的普通高等学校招生数据的转换,能同时适应高招、中招、三校生系统。
关键词 C#,ADO.NET,高等学校,学籍管理,C/S,DBF,SQL Server

 一、引言
    在学校,尤其是在各大普通高校,学籍信息是学校的一项重要的数据资源,学籍管理也是学校的一项常规性的重要工作。学籍管理系统不但能使学生管理人员从复杂的学籍管理任务中解脱出来,而且对于推动教学的发展也起到非常重要的作用!而长期以来,学籍管理中学生信息大都是依赖人工录入的,面对如此众多的学籍信息,其工作量可想而知。不仅仅浪费了大量的人力物力,而且由于人工管理存在着大量的不可控因素,造成了学籍管理的某些不规范。
    普通高校新生学籍电子注册工作是当前加强高等教育管理、提高教育质量的必要措施,是从源头上治理违规招生、规范办学行为的重要举措。为此,教育部高校学生司发布了《普通高等学校新生学籍电子注册暂行办法》(教学[2007]3号),文件要求新生学籍电子注册工作与新生入学复查同步进行,并同时要求各高校建立自己的学籍查询网站,与教育部公布学籍信息进行对比核查。
    近几年,随着普通高等学校招生网上录取逐步推广,快速、准确地获取已录取考生信息成为可能。新生录取结束后,将考生的信息导入到新生管理系统中,实现新生分配专业、分配班级、生成学号、报到注册或退档,以及必要的调系(专业)、调班等处理,并适时导入学籍管理数据库。
二、高招导出数据表结构分析
    1.高招导出数据表结构
    目前,普通高校招生网上录取已在全国范围内实现,各省网上录取结束后,就可以导出本校录取的考生信息。其实,导出的内容是25个扩展名.DBF的数据表,录取的考生信息就分散在这25个DBF文件中,如表1所示。
                              表1 高考导出数据表明细   

序号

数据表名称

含义

1

T_TDD.DBF

投档单:各省结构不同

2

T_KSJL.DBF

考生简历

3

T_JHK.DBF

专业招生计划

4

T_QBJHK.DBF

专业招生计划

5

T_TJXX.DBF

体检信息

6

T_TDDW.DBF

投档单位

7

T_KSHKCJ.DBF

会考成绩

8

TD_XBDM.DBF

性别:1/2

9

TD_MZDM.DBF

民族:汉族/蒙古族/回族/

10

TD_ZZMMDM.DBF

政治面貌:中共党员/

11

TD_WYYZDM.DBF

外语语种:各省表示不同

12

TD_PCDM.DBF

批次:各省表示不同

13

TD_KLDM.DBF

科类:1文史/5理工/  各省不同

14

TD_DQDM.DBF

地区代码:(省内)各省内容不同

15

TD_KSLBDM.DBF

考生类别:城镇应届/城镇往届/

16

TD_TJJLDM.DBF

体检记录:合格/专业受限/不合格

17

TD_ZCDM.DBF

考生特征,政策代码:省级三好/

18

TD_BYLBDM.DBF

毕业类别:0高中毕业/

19

TD_KSLXDM.DBF

考试类型:0春季统考/1秋季统考/

20

TD_LQFSDM.DBF

录取方式:20统招/21定向/

21

TD_TDYYDM.DBF

退档原因

22

TD_XTDWDM.DBF

系统代码

23

TD_ZYTZDM.DBF

专业特征

24

TD_JHXZDM.DBF

计划性质

25

TD_CJXDM.DBF

特定成绩结构

    其中,以TD_开头的18个DBF表文件,大多具有代码和代码所对应中文名称两个有用字段,常用数据之间的关联关系如图1所示。

    图1 常用13个DBF表之间的关系
    2.可获取的考生信息
    (1)考生基本信息表
    所有考生的基本信息数据都在T_TDD.DBF(投档单)数据表中。出于网上招生录取实时性、网速及数据冗余等方面考虑,T_TDD.DBF表中大量采用代码表示考生的信息,可直接获取的考生基本信息如表2所示。
                                表2 T_TDD.DBF可直接获取的考生基本信息

序号

字段名

类型

长度

含义

1

KSH

字符

14

考生号

2

ZKZH

字符

9

准考证号,部分省为空

3

XM

字符

64

姓名

4

CSNY

日期

8

出生日期

5

SFZH

字符

18

身份证号,部分中考考生为空

6

ZXMC

字符

30

毕业学校(单位)

7

CJ

数值

18.9

入学成绩

8

JTDZ

字符

128

家庭地址,录取期间用的

9

YZBM

字符

6

家庭邮编,导入学籍系统后改

10

LXDH

字符

20

家庭电话

11

DQDM

字符

6

生源地代码,各省表示不同

12

ZYZYTJ

字符

1

是否允许专业调剂

13

BZ

字符

254

备注

    这些字段内容可直接转换至新生数据表。而更多的信息是用代码表示的,为了获取相应的考生信息,需要和对应的数据表关联,才能导入相关信息。
    (2)考生简历表
    考生简历数据在T_KSJL.DBF数据表中,其结构如表3所示。相关简历信息通过“考生号”与考生基本信息T_TDD.DBF(投档单)数据表关联获得。
                        表3 T_KSJL.DBF考生简历信息表结构

序号

字段名

类型

长度

含义

1

KSH

字符

14

考生号

2

QSRQ

日期

8

自何年何月

3

ZJRQ

日期

8

至何年何月

4

JL

字符

64

在何单位学习或工作

5

RHZW

字符

64

任何职务

6

ZMR

字符

64

证明人

3.获取招生计划
录取专业名称、教育部专业编号、招生人数等计划信息在数据表T_JHK.DBF中。
4.代码中涉及的关键数据
    (1)考生号
    普通高考考生号(14位)编排办法及代表意义如下:
   
    图2 考生号构成关系
    其中:
1)第1、2位为年份的后两位数。如2007年,第1、2位为“07”
2)第3至8位共6位为行政区划代码(国标码)。
3)第9位为考试类型代码。编码如下:
    0 春季统考 1 秋季统考 2 保送 3 小语种 4 二学位
    5 实践青年 6 职教师资 7 运动训练民族体育 8三校生(高职班) 9 自定义项(单考)
4)第10位为科类代码。编码如下:
    1 文史 3艺术(文) 4体育 (文) 5理工
    7艺术(理) 8 体育(理) 9 单独考试
5)如果考生号第10位为“3”或“7”,即该考生号为艺术类考生的考生号,则第11位就为该考生号的艺术类加试类别代码,定义为:美术类——2(3,4备用);音乐类——6(7,8备用);其他——9(0,1备用)。
6)普通三校生考生号的第9、10位为“85”。四年制中专免试生的考生号,第9、10位为“85”,但第11位设为“9”,以区分与普通三校生的不同。
7)实践班的考生号第9、10位为“55”。
8)第11位至第14位为流水号。
    (2)生源地省(市、自治区)代码及名称
    招生录取是按省(市、自治区)分别进行的。从导出的数据表中正确取出省(市、自治区)代码和名称也是必要的,以便确定考生的籍贯,同时,学生毕业也需要该信息。
三、新生数据表结构设计
1.创建接收新生信息的数据表
    根据上述对高招导出数据表结构的分析,根据新生管理要求分别建立新生基本信息数据表NewStudentInfo和新生简历数据表NewStudentIntro,具体参数见图3和图4。

    图3 新生基本信息表NewStudentInfo结构

    图4 新生简历表NewStudentIntro结构
    学生基本信息表除了对应导入的相应字段外,还要增加一些新生管理或学籍管理中所需的必要字段,如:学号、班级名称、校内的专业编号、报到标志等。
    为保证数据集方式更新的可行性,新生基本信息数据表NewStudentInfo和新生简历数据表NewStudentIntro中必须要有标识列NewStudentID和NewStudentIntroID。
四、代码描述(设计与实现)
    1.主窗体设计

    图5 主窗体
    首先,启动Visual Studio .NET 20003,新建一个项目。然后在“新建项目”对话框中选择“Visual C#项目”的“Windows应用程序”,在“名称”文本框中输入同一目录下唯一名称来命名该项目,在“位置”文本框中输入该项目保存的目录或单击“浏览”按钮选择确定目录。单击“确定”按钮后出现设计窗体。
    依次添加下述主要功能控件:
Label控件:lblFilesPath(路径)、label2、label3
Button控件:btnFilePath(…钮)、btnOK(数据导入)、btnClose(关闭)
ListBox控件:lbFiles(DBF文件列表框)
ComboBox控件:cbProvinces(生源地组合框)
DataGrid控件:dataGrid1(考生信息表)
StatusBar控件:statusBar1(状态行)
适当调整各控件的位置和大小。
加载窗体事件核心代码及用到的全局量如下:
private string conStr; // 数据库连接串
private DataSet m_Ds; // 数据集
private DataTable m_provinces; // 数据表
private void Form1_Load(object sender, EventArgs e)
{ // 获取省(市、自治区)代码表 => m_provinces
try
{ // 填充m_Provinces
OleDbConnection conn = new OleDbConnection(conStr);
string sql = "SELECT Code,CodeMean FROM Code";
OleDbCommand cmd = new OleDbCommand(sql, conn);
new OleDbDataAdapter(cmd).Fill(m_Provinces);
// 填充cbProvinces
this.cbProvinces.DataSource = m_Provinces;
this.cbProvinces.DisplayMember = "CodeMean";
this.cbProvinces.ValueMember = "Code";
this.cbProvinces.Visible = false;
}
catch (Exception exception1)
{
MessageBox.Show(exception1.Message);
}
}
    该程序的功能是从Code数据表中读出省(市、自治区)的代码Code和名称CodeMean,填充到DataTable表m_Provinces中,同时赋值给ComboBox组合框cbProvinces,用以确定生源地所在的省(市、自治区)。
    2.分省录取数据文件夹选择对话框设计
    在主窗体中,btnFilePath按钮控件用于打开浏览文件夹对话框,选择后的文件夹路径信息显示在lblFilesPath标签控件中。从该文件夹中取出所有DBF文件显示在lbFiles列表框中,同时在label2标签中显示获取的数据文件的个数。
    如果文件夹路径为非空,则通过Browser()方法获取高招导出数据表关联的考生信息。

    图6
核心代码如下:
private void btnFilePath_Click(object sender, EventArgs e)
{
string FilePath = "";// 获取DBF数据文件路径文件夹
try
{
if (this.fbdFiles.ShowDialog() != DialogResult.OK)
return; // 取消返回
FilePath = fbdFiles.SelectedPath.Trim();
this.lblFilesPath.Text = "路径:" + FilePath;
this.lbFiles.Items.Clear();
int FileCount = 0;
FileInfo[] infoArray1 = new DirectoryInfo(FilePath).GetFiles();
foreach (FileInfo info2 in infoArray1)
{
if ( info2.Extension.ToUpper()==".DBF" )
{ // 只填充DBF文件并统计个数
this.lbFiles.Items.Add(info2.Name.Trim());
FileCount++;
}
}
label2.Text="数据文件列表:("+FileCount+"个文件)";
}
catch (Exception exception1)
{
MessageBox.Show(exception1.Message);
}
if (FilePath != "")
Browser(FilePath); // 浏览考生数据
}
    3.获取高招导出数据表关联的考生信息
    通过Browser()方法获取高招导出数据表关联的考生信息。根据对高招导出数据表的结构分析可知:
    (1)考生信息数据主要存放在图1所示的DBF相关表中。通过连接查询并加载连接字段条件将多个表连接起来,从而实现从多个表中检索出所需要的数据。
    (2)由于T_TDD.DBF表中多数为代码字段,代码字段的真实含义字段在另一个代码表中;这样,就必须以T_TDD.DBF表的每行数据去匹配代码表的数据列,符合连接条件的数据直接返回到结果集中。对那些不符合连接条件的列将被填上NULL值后再返回到结果集中(不同省(市、自治区)对考生基本信息的采集方式并不一致,有的省(市、自治区)对考生的某些信息字段并没有录入,这样,相应的代码字段为空)。
    如果将T_TDD.DBF作为主表放在连接条件的左边,那么,使用SQL Server的Left Outer Join(左外部连接)查询即可获取考生的全部有用信息。(对T_TDD.DBF表不加限制,而只限制相应的代码表)
    (3)获取的考生基本信息存放在DataSet对象的DataTable对象中。
DataSet是ADO.NET结构的主要组件,它是从数据源中检索到的数据在内存中的缓存。DataSet对象可以存储数据库中信息的拷贝,可以在切断数据库连接时处理这个本地拷贝。DataSet是一般性的适用于任何数据库。DataSet还可以按任何顺序读行和修改行。可以在DataSet中修改这个本地拷贝,然后通过DataAdapter对象在数据集和数据库之间同步记录。
    DataSet是包含表和这些表之间关系的集合。每个表包含一个列集合。这些对象代表了数据集的模式。每个表都有多个行,表示这个数据集所保持的数据。这些行记得它们的初始状态和当前状态,以便数据集可以跟踪发生了何种改变。
    DataSet中可以存储多个DataTable对象。DataTable表示内存中数据的一个表。
核心代码如下:
private void Browser(string FilePath)
{ // 获取考生信息
if (FilePath == "") return;
this.m_Conns.ConnectionString = "Provider=VFPOLEDB.1;Collating Sequence=MACHINE;Data Source=" + FilePath;
try
{
this.Cursor = Cursors.WaitCursor;
this.m_Ds.Clear();
this.m_Conns.Open();
// 获取考生基本信息
string sql = "SELECT T_TDD.KSH, T_TDD.XM, T_TDD.CSNY, T_TDD.XBDM, TD_XBDM.XBMC, T_TDD.MZDM, TD_MZDM.MZMC, TD_ZZMMDM.ZZMMMC, T_TDD.TJJLDM, TD_TJJLDM.TJJLMC, T_TDD.SFZH, T_TDD.ZXMC, T_TDD.WYYZDM, TD_WYYZDM.WYYZMC, TD_KSLBDM.KSLBMC, TD_DQDM.DQDM, TD_DQDM.DQMC, T_TDD.JTDZ, T_TDD.YZBM, T_TDD.LXDH, T_TDD.CJ, T_TDD.LQZY, T_JHK.ZYDM, T_JHK.ZYMC, T_TDD.PCDM, TD_PCDM.PCMC, T_TDD.KLDM, TD_KLDM.KLMC, T_TDD.KSTZ, TD_ZCDM.ZCMC, T_TDD.ZYZYTJ, T_TDD.BZ FROM T_TDD LEFT OUTER JOIN T_JHK ON T_TDD.PCDM = T_JHK.PCDM AND T_TDD.LQZY = T_JHK.ZYDH AND T_TDD.KLDM = T_JHK.KLDM LEFT OUTER JOIN TD_XBDM ON T_TDD.XBDM = TD_XBDM.XBDM LEFT OUTER JOIN TD_MZDM ON T_TDD.MZDM = TD_MZDM.MZDM LEFT OUTER JOIN TD_ZZMMDM ON T_TDD.ZZMMDM = TD_ZZMMDM.ZZMMDM LEFT OUTER JOIN TD_TJJLDM ON T_TDD.TJJLDM = TD_TJJLDM.TJJLDM LEFT OUTER JOIN TD_WYYZDM ON T_TDD.WYYZDM = TD_WYYZDM.WYYZDM LEFT OUTER JOIN TD_DQDM ON T_TDD.DQDM = TD_DQDM.DQDM LEFT OUTER JOIN TD_PCDM ON T_TDD.PCDM = TD_PCDM.PCDM LEFT OUTER JOIN TD_KLDM ON T_TDD.KLDM = TD_KLDM.KLDM LEFT OUTER JOIN TD_ZCDM ON T_TDD.KSTZ = TD_ZCDM.ZCDM LEFT OUTER JOIN TD_KSLBDM ON T_TDD.KSLBDM = TD_KSLBDM.KSLBDM";
OleDbCommand cmd = new OleDbCommand(sql,m_Conns);//
new OleDbDataAdapter(cmd).Fill(m_Ds, "KsInfo");
if (this.m_Ds.Tables["KsInfo"].Rows.Count < 1 )
return; // 无考生,返回
this.dataGrid1.DataSource = m_Ds.Tables["KsInfo"];
// 获取生源地所在省(市、自治区)代码ProvinceID及名称ProvinceName
DataView dv = new DataView(this.m_Provinces);
DataTable dt = this.m_Ds.Tables["KsInfo"];
string KSH=dt.Rows[0]["KSH"].ToString().Trim();//考生号
string ProvinceID = KSH.Substring(2, 2);
string ProvinceName = "";
if (KSH.Length ==14)
{
dv.RowFilter = "Code = " + ProvinceID;
if (dv.Count > 0)
ProvinceName = dv[0]["CodeMean"].ToString().Trim();
this.cbProvinces.SelectedValue = ProvinceID;
this.cbProvinces.Enabled = false;
}
else
{
MessageBox.Show("无法获取生源地所在省(市、自治区),请手工选择!","操作提示");
this.cbProvinces.Enabled = true;
}
this.cbProvinces.Visible = true;
// 获取考生简历
OleDbCommand cmd1 = new OleDbCommand("SELECT * FROM T_KSJL", this.m_Conns);
new OleDbDataAdapter(cmd1).Fill(m_Ds, "T_KSJL");
// 创建 KsInfo 和 T_KSJL 的父/子表关系
this.m_Ds.Relations.Clear();//清除集合中的所有关系
DataTable parentTable= m_Ds.Tables["KsInfo"];
DataTable childTable = m_Ds.Tables["T_KSJL"];
DataColumn parentCol = parentTable.Columns["KSH"];
DataColumn childCol = childTable.Columns["KSH"];
DataRelation relOrder = new DataRelation("简历", parentCol, childCol);
m_Ds.Relations.Add(relOrder);
this.dataGrid1.CaptionText = "考生基本信息";
this.dataGrid1.DataSource = parentTable;
this.dataGrid1.AllowNavigation = true;
}
catch (Exception exception1)
{
MessageBox.Show(exception1.Message);
return;
}
finally
{
this.m_Conns.Close();
this.statusBar1.Text = "记录数:" + this.m_Ds.Tables["KsInfo"].Rows.Count;
this.btnOK.Enabled = true; // 使能“导入”按钮
this.Cursor = Cursors.Default;
}
}
    4.将获取的考生信息导入到新生数据表中
    为保证数据一致性,避免重复导入,一般采用存储过程或数据集更新模式完成。但由于存储过程方式对浮点型数据(如本例的成绩)处理不够理想,所以,本程序使用了数据集更新模式。
    同时,采用数据集更新模式要求数据表中必须有标识列,否则,回出现“对于不返回任何键列信息的SelectCommand不支持DeleteCommand、UpdateCommand的动态SQL生成”错误信息。
核心代码如下:
private void btnOK_Click(object sender, System.EventArgs e)
{
this.m_Conna.ConnectionString = conStr;
try
{
this.Cursor = Cursors.WaitCursor;
// 考生基本信息
string sql = "SELECT * FROM NewStudentInfo";
OleDbCommand cmd = new OleDbCommand(sql, m_Conna);
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
OleDbCommandBuilder cb = new OleDbCommandBuilder(da);
da.InsertCommand = cb.GetInsertCommand();
da.DeleteCommand = cb.GetDeleteCommand();
da.UpdateCommand = cb.GetUpdateCommand();
da.Fill(this.m_Ds, "NewStudentInfo");
DataTable table1 = m_Ds.Tables["NewStudentInfo"];
DataView dv1 = new DataView(table1);
//
DataView dv2 = new DataView(this.m_Provinces);
DataTable table2 = this.m_Ds.Tables["KsInfo"];
for (int n = 0; n < table2.Rows.Count; n++)
{
DataRow R = table2.Rows[n];
string KSH = R["KSH"].ToString().Trim();//考生号
string ProvinceID = KSH.Substring(2, 2);
string ProvinceName = "";
if (KSH.Length !=14)
{
ProvinceID = cbProvinces.SelectedValue.ToString();
}
dv2.RowFilter = "Code = " + ProvinceID;
if (dv2.Count > 0)
ProvinceName = dv2[0]["CodeMean"].ToString().Trim();
dv1.RowFilter = "ExamineNo=" + KSH;
DataRow r; //
if (dv1.Count > 0) //该记录已存在
r = dv1[0].Row; //
else
r = table1.NewRow(); //
r["ExamineNo"] = KSH;
r["Hometown"] = ProvinceName;
r["SID"] = R["SFZH"].ToString().ToUpper();
r["StudentName"] = R["XM"];
r["Sex"] = R["XBMC"];
// …其它同上行格式(略)
r["IsCheckIn"] = false; // 未报到
if (dv1.Count <= 0) //该记录不存在
table1.Rows.Add(r); //
} // end of for n
da.Update(table1); // 更新考生基本信息
this.dataGrid1.DataSource = table1;
// 考生简历
sql = "SELECT * FROM NewStudentIntro";
cmd = new OleDbCommand(sql, this.m_Conna);
da = new OleDbDataAdapter(cmd);
cb = new OleDbCommandBuilder(da);
da.InsertCommand = cb.GetInsertCommand();
da.Fill(this.m_Ds, "NewStudentIntro");
table1 = this.m_Ds.Tables["NewStudentIntro"];
DataView dv3 = new DataView(table1);
table2 = m_Ds.Tables["T_KSJL"]; // 新的考生简历
for (int n = 0; n < table2.Rows.Count; n++)
{
DataRow R = table2.Rows[n];
dv3.RowFilter = "ExamineNo='" + R["ksh"] + "' AND BeginDate='" + R["qsrq"] + "' AND EndDate='" + R["zjrq"] + "' AND Company='" + R["jl"] + "'AND HeadShip='" + R["rhzw"] + "' AND Testifier='" + R["zmr"] + "'";
if (dv3.Count > 0) continue;
DataRow r = table1.NewRow(); // 新增一个空行
r["ExamineNo"] = R["ksh"]; // 考生号
r["BeginDate"] = R["qsrq"]; // 开始日期
r["EndDate"] = R["zjrq"]; // 结束日期
r["Company"] = R["jl"]; // 所在单位
r["HeadShip"] = R["rhzw"]; // 职务
r["Testifier"] = R["zmr"]; // 证明人
table1.Rows.Add(r);
}
// 更新考生简历
da.Update(m_Ds.Tables["NewStudentIntro"]);
}
catch (Exception exception1)
{
MessageBox.Show(exception1.Message);
return;
}
finally
{
this.btnOK.Enabled = false; // 禁止“数据导入”
this.Cursor = Cursors.Default;
}
}
五、测试与验证
    因为本程序要读取DBF格式的考生信息数据表,所以执行该程序的客户端需要安装Microsoft OLE DB Provider for Visual FoxPro提供程序或安装Visual FoxPro 6.0以上版本。
本程序要求本地或远程安装SQL Server数据库,以便将获取的考生信息写入SQL Server数据库。修改数据库连接串,也可实现写入Access等其他种类数据库。
六、结语
    本程序在Visual Studio .NET 2003和MS SQL Server 2000环境下调试通过,在我校新生管理中得到实际应用。对2006年和2007年13个省(市、自治区)的高招录取数据均调试通过。
分专业、分配班级、生成学号、导入学籍管理数据表、新生报到与退档(未报到)处理、新生信息编辑等新生管理部分,不在本文讨论范围内,暂不涉及。

参考文献
[1] MSDN.http://msdn2.microsoft.com/zh-cn/default.aspx

(电脑编程技巧与维护杂志社版权所有。未经许可不得转载。)
 

 
 
     
     
 
2008 Copyright.《电脑编程技巧与维护》杂志社 版权所有