Skip to content

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

结构

SS
员工社会保险号 - 主键
NOM
员工姓名
prenom
其名字
ADRESSE
他的地址
VILLE
他的城市
CODEPOSTAL
他的邮政编码
INDICE
其处理索引 - 表 [INDEMNITES] 中字段 [INDICE] 的外键

其内容可能如下:


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é
INDICE
薪资指数 - 主键
BASEHEURE
每小时看护服务的欧元净价
ENTRETIENJOUR
每小时看护的欧元生活津贴
REPASJOUR
每日看护的餐费补贴(欧元)
INDEMNITESCP
带薪休假补贴。该金额为基本工资的百分比。

其内容可能如下:

需注意,不同保育员的津贴可能有所不同。这些津贴实际上是通过保育员的薪级指数与特定保育员关联的。 例如,薪级指数为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 上:
  1. 右键单击 [Databases] / 附加
  2. 通过按钮选择文件 [dbpam.mdf](图中未显示的 [Add])
  3. 该附件将生成一个名为 BD 的新文件,该文件此前不应存在。在此,在 [Attach As] 字段中,我们为新文件 BD 命名为 [dbpam2]。
  4. 可以看到新的 BD 及其表

这种将BD附加到其他文件的技术,对于将BD从一个岗位转移到另一个岗位非常有用,我们在此处有时会使用它。

3.2. 保姆工资的计算方法

下面介绍保育员月薪的计算方法。我们以玛丽·朱维纳尔女士为例,她在当月工作了20天,共计150小时。

计算时考虑以下要素:

[TOTALHEURES]: total des
 heures travaillées dans le
 mois

[TOTALJOURS]: total des jours
 travaillés dans le mois
[TOTALHEURES]=150
[TOTALJOURS]= 20
保育员的基本工资按以下公式计算:
[SALAIREBASE]=([TOTALHEURES]*
[BASEHEURE])*(1+
[INDEMNITESCP]/100)
[SALAIREBASE]=(150*[2.1])*(1+0.15)= 362,25
需从该基本工资中扣除一定数额的社会保险费:

Contribution sociale
 généralisée et contribution
 au remboursement de la dette
 sociale : [SALAIREBASE]*[CSGRDS/100]

Contribution sociale
 généralisée déductible :
 [SALAIREBASE]*[CSGD/100]

Sécurité sociale, veuvage,
 vieillesse :
 [SALAIREBASE]*[SECU/100]
Retraite Complémentaire + 
AGPF + Assurance Chômage : 
[SALAIREBASE]*[RETRAITE/100]
CSGRDS : 12,64
CSGD : 22,28
Sécurité sociale : 34,02
Retraite : 28,55
社会保险费总额:
[COTISATIONSSOCIALES]=[SALAIR
EBASE]*(CSGRDS+CSGD+SECU+RETR
[COTISATIONSSOCIALES]=97,48
此外,家庭保育员每工作一天,有权获得生活津贴和餐费补贴。为此,她将获得以下补贴:

[Indemnités]=[TOTALJOURS]*(EN
TRETIENJOUR+REPASJOUR)
[INDEMNITES]=104
最终,应支付给保育员的净工资如下:
[SALAIREBASE]-
[COTISATIONSSOCIALES]+
[INDEMNITÉS]
[salaire NET]=368,77

3.3. 提醒 ADO.NET

薪资计算应用程序需要数据库中的信息 [dbpam]。其架构如下:

  • 在 [1] 中,用户发起请求
  • 在 [2] 中,薪资应用程序处理该请求。
  • 此时,它可能需要数据库中的数据。于是,它向 SGBD 使用的 ADO.NET 提供程序发出请求。
  • 该提供程序调用数据库 [5],并将结果返回给提供程序 ADO.NET,后者再将结果上报给应用程序
  • 该应用程序利用这些结果,为用户生成响应 [5]

现在,我们回顾一下 ADO.NET 提供商向其 [3] 客户端提供的主要接口。

连接模式下,该应用程序:

  1. 与数据源建立连接
  2. 对数据源进行读写操作
  3. 关闭连接

以下三个 ADO.NET 接口主要涉及这些操作:

  • IDbConnection,封装了连接的属性与方法。
  • IDbCommand,封装已执行的 SQL 命令的属性和方法。
  • IDataReader,封装了 SQL Select 命令结果的属性和方法。

IDbConnection 接口

用于管理与数据库的连接。该接口的M方法和P属性包括以下内容:

名称
类型
作用
ConnectionString
P
数据库连接字符串。它指定了与特定数据库建立连接所需的所有参数。
Open
M
建立与由 ConnectionString 定义的数据库的连接
Close
M
关闭连接
BeginTransaction
M
开始事务。
State
P
连接状态:ConnectionState.Closed ConnectionState.Open ConnectionState.ConnectingConnectionState.Executing, ConnectionState.Fetching, ConnectionState.Broken

如果 Connection 是实现接口 IDbConnection 的类,则可以按以下方式建立连接:

1
2
3
IDbConnection connexion=new Connection();
connexion.ConnectionString=...;
connexion.Open();

接口 IDbCommand

用于执行 SQL 命令或存储过程。该接口的 M 方法和 P 属性包括以下内容:

名称
类型
作用
CommandType
P
指定要执行的内容 - 其值取自一个枚举:
- CommandType.Text:执行在属性 CommandText 中定义的命令 SQL。这是默认值。
- CommandType.StoredProcedure:执行数据库中的存储过程
CommandText
P
- 若 CommandType= CommandType.Text,则需执行的命令 SQL 的文本
- 若 CommandType= CommandType.StoredProcedure,则要执行的存储过程名称
Connection
P
用于执行命令 SQL 的连接 IDbConnection
Transaction
P
用于执行命令 SQL 的交易 IDbTransaction
Parameters
P
已配置的 SQL 命令的参数列表。命令 update articles set price=price*1.1 where id=@id 包含参数 @id。
ExecuteReader
M
用于执行命令 SQL Select。将获得一个对象 IDataReader,该对象表示 Select 的结果。
ExecuteNonQuery
M
用于执行 SQL 命令(更新、插入、删除)。将返回受该操作影响的行数(更新、插入、删除)。
ExecuteScalar
M
要执行一个仅返回单一结果的查询,例如:select count(*) from articles,请使用命令 SQL Select
CreateParameter
M
用于创建已配置的 SQL 命令的 IDbParameter 参数。
Prepare
M
用于优化带参数查询的执行,当该查询使用不同的参数多次执行时。

如果 Command 是实现接口 IDbCommand 的类,则不带事务的 SQL 命令的执行形式如下:

// 建立连接 
IDbConnection connexion=...
connexion.Open();
// 准备命令
IDbCommand commande=new Command();
commande.Connection=connexion;
// 执行 select 语句
commande.CommandText="select ...";
IDbDataReader reader=commande.ExecuteReader();
...
// 执行更新、插入、删除命令
commande.CommandText="insert ...";
int nbLignesInsérées=commande.ExecuteNonQuery();
...
// 关闭连接
connexion.Close();

接口 IDataReader

用于封装 SQL 和 Select 命令的结果。 一个 IDataReader 对象表示一个包含行和列的表,该表按顺序处理:先处理第一行,然后是第二行,依此类推。该接口的 M 方法和 P 属性包括以下内容:

名称
类型
角色
FieldCount
P
表的列数IDataReader
GetName
M
GetName(i) 返回表 IDataReader 中第 i 列的名称。
Item
P
Item[i] 代表表 IDataReader 中当前行的第 i 列。
Read
M
跳转到表 IDataReader 的下一行。如果读取成功,则返回布尔值 True;否则返回 False
Close
M
关闭表 IDataReader
GetBoolean
M
GetBoolean(i):返回表 IDataReader 中当前行第 i 列的布尔值。 其他类似的方法如下:GetDateTimeGetDecimalGetDoubleGetFloatGetInt16GetInt32GetInt64GetString
Getvalue
M
Getvalue(i):将表 IDataReader 中当前行第 i 列的值转换为类型 object
IsDBNull
M
IsDBNull(i) 若表 IDataReader 当前行第 i 列无值(由值 SQL NULL 表示),则返回 True

IDataReader 对象的查询通常如下所示:

// 建立连接 
IDbConnection connexion=...
connexion.Open();
// 命令准备
IDbCommand commande=new Command();
commande.Connection=connexion;
// 执行SELECT语句
commande.CommandText="select ...";
IDataReader reader=commande.ExecuteReader();
// 结果处理
while(reader.Read()){
     // 处理当前行
        ...
}
// 关闭读卡器
reader.Close();
// 关闭连接
connexion.Close();