3. 案例研究
我们希望编写一个.NET应用程序,允许用户模拟计算某市镇“幼儿之家”协会中保育员的工资。 我们将既关注该应用程序的代码组织结构,也关注代码本身。
3.1. 数据库
用于生成工资单的静态数据存储在名为 dbpam(pam=保育员工资)的 SQL Server Express 数据库中。该数据库的管理员名为 sa,密码为 msde。
![]() |
该数据库包含三个表:EMPLOYES、COTISATIONS 和 INDEMNITES,其结构如下:
Table EMPLOYES : rassemble des informations sur les différentes assistantes maternelles
结构:
![]() |
|
其内容可能如下:
Table COTISATIONS : rassemble les taux des cotisations sociales prélevées sur le salaire
结构:
![]() |
其内容可能如下:
社会保险费率与员工无关。上表仅有一行。
Table INDEMNITES : rassemble les différentes indemnités dépendant de l'indice de l'employé
![]() |
|
其内容可能如下:
![]() |
需注意,不同保育员的津贴可能有所不同。这些津贴实际上是通过保育员的薪级指数与特定保育员关联的。 例如,薪级指数为2的玛丽·朱维纳尔女士(表EMPLOYES),其时薪为2.1欧元(表INDEMNITES)。
这三张表之间的关系如下:
![]() |
EMPLOYES表的INDICE列与INDEMNITES表的INDICE列之间存在外键关系。
由此创建的数据库 [dbpam] 会在 SQL Server Express 文件夹中生成两个文件:
![]() |
文件[dbpam.mdf, dbpam_log.ldf]可以转移到另一台机器上,并重新关联到该机器上的SGBD SQL Server Express。操作步骤如下:
- 将 BD 和 [dbpam] 文件复制到一个文件夹中
![]() |
- 启动 SQL Server Express
- 配合 SQL Server Management Studio Express 客户端,将文件 [dbpam.mdf] 附加到 SGBD 上:
![]() |
![]() |
- 右键单击 [Databases] / 附加
- 通过按钮选择文件 [dbpam.mdf](图中未显示的 [Add])
- 该附件将生成一个名为 BD 的新文件,该文件此前不应存在。在此,在 [Attach As] 字段中,我们为新文件 BD 命名为 [dbpam2]。
- 可以看到新的 BD 及其表
这种将BD附加到其他文件的技术,对于将BD从一个岗位转移到另一个岗位非常有用,我们在此处有时会使用它。
3.2. 保姆工资的计算方法
下面介绍保育员月薪的计算方法。我们以玛丽·朱维纳尔女士为例,她在当月工作了20天,共计150小时。
计算时考虑以下要素: | | |
保育员的基本工资按以下公式计算: | ||
需从该基本工资中扣除一定数额的社会保险费: | | |
社会保险费总额: | ||
此外,家庭保育员每工作一天,有权获得生活津贴和餐费补贴。为此,她将获得以下补贴: | | |
最终,应支付给保育员的净工资如下: |
3.3. 提醒 ADO.NET
薪资计算应用程序需要数据库中的信息 [dbpam]。其架构如下:
![]() |
- 在 [1] 中,用户发起请求
- 在 [2] 中,薪资应用程序处理该请求。
- 此时,它可能需要数据库中的数据。于是,它向 SGBD 使用的 ADO.NET 提供程序发出请求。
- 该提供程序调用数据库 [5],并将结果返回给提供程序 ADO.NET,后者再将结果上报给应用程序
- 该应用程序利用这些结果,为用户生成响应 [5]
现在,我们回顾一下 ADO.NET 提供商向其 [3] 客户端提供的主要接口。
在连接模式下,该应用程序:
- 与数据源建立连接
- 对数据源进行读写操作
- 关闭连接
以下三个 ADO.NET 接口主要涉及这些操作:
- IDbConnection,封装了连接的属性与方法。
- IDbCommand,封装已执行的 SQL 命令的属性和方法。
- IDataReader,封装了 SQL Select 命令结果的属性和方法。
IDbConnection 接口
用于管理与数据库的连接。该接口的M方法和P属性包括以下内容:
名称 | 类型 | 作用 |
P | 数据库连接字符串。它指定了与特定数据库建立连接所需的所有参数。 | |
M | 建立与由 ConnectionString 定义的数据库的连接 | |
M | 关闭连接 | |
M | 开始事务。 | |
P | 连接状态:ConnectionState.Closed、 ConnectionState.Open、 ConnectionState.Connecting、 ConnectionState.Executing, ConnectionState.Fetching, ConnectionState.Broken |
如果 Connection 是实现接口 IDbConnection 的类,则可以按以下方式建立连接:
接口 IDbCommand
用于执行 SQL 命令或存储过程。该接口的 M 方法和 P 属性包括以下内容:
名称 | 类型 | 作用 |
P | 指定要执行的内容 - 其值取自一个枚举: - CommandType.Text:执行在属性 CommandText 中定义的命令 SQL。这是默认值。 - CommandType.StoredProcedure:执行数据库中的存储过程 | |
P | - 若 CommandType= CommandType.Text,则需执行的命令 SQL 的文本 - 若 CommandType= CommandType.StoredProcedure,则要执行的存储过程名称 | |
P | 用于执行命令 SQL 的连接 IDbConnection | |
P | 用于执行命令 SQL 的交易 IDbTransaction | |
P | 已配置的 SQL 命令的参数列表。命令 update articles set price=price*1.1 where id=@id 包含参数 @id。 | |
M | 用于执行命令 SQL Select。将获得一个对象 IDataReader,该对象表示 Select 的结果。 | |
M | 用于执行 SQL 命令(更新、插入、删除)。将返回受该操作影响的行数(更新、插入、删除)。 | |
M | 要执行一个仅返回单一结果的查询,例如:select count(*) from articles,请使用命令 SQL Select。 | |
M | 用于创建已配置的 SQL 命令的 IDbParameter 参数。 | |
M | 用于优化带参数查询的执行,当该查询使用不同的参数多次执行时。 |
如果 Command 是实现接口 IDbCommand 的类,则不带事务的 SQL 命令的执行形式如下:
接口 IDataReader
用于封装 SQL 和 Select 命令的结果。 一个 IDataReader 对象表示一个包含行和列的表,该表按顺序处理:先处理第一行,然后是第二行,依此类推。该接口的 M 方法和 P 属性包括以下内容:
名称 | 类型 | 角色 |
P | 表的列数IDataReader | |
M | GetName(i) 返回表 IDataReader 中第 i 列的名称。 | |
P | Item[i] 代表表 IDataReader 中当前行的第 i 列。 | |
M | 跳转到表 IDataReader 的下一行。如果读取成功,则返回布尔值 True;否则返回 False。 | |
M | 关闭表 IDataReader。 | |
M | GetBoolean(i):返回表 IDataReader 中当前行第 i 列的布尔值。 其他类似的方法如下:GetDateTime、GetDecimal、GetDouble、GetFloat、GetInt16、 GetInt32、GetInt64、GetString。 | |
M | Getvalue(i):将表 IDataReader 中当前行第 i 列的值转换为类型 object。 | |
M | IsDBNull(i) 若表 IDataReader 当前行第 i 列无值(由值 SQL NULL 表示),则返回 True。 |
对 IDataReader 对象的查询通常如下所示:










