一:三层的交互:
二:文件夹结构:
三:人员管理系统 –步骤
1. 用户登录
a) 界面:
b) 实现过程:
i. UI层:收集用户信息,将请求传递给BLL业务层进行处理
ii. BLL业务层传递用户操作请求给DAL数据访问层
iii. DAL数据访问层根据用户请求查询出相应数据行,将数据行转换为实体对象并且返回给BLL业务逻辑层。
iv. BLL业务层将数据访问层的返回数据返回给UI层
v. UI层接收返回的数据,判断是否成功登录。
vi. 如果登录成功则关闭当前登录窗体,打开“人员管理主窗体”
c) 相关代码:
i. UI层代码:
#region登录 +void btnLogin_Click(object sender, EventArgs e)
///<summary>
///登录
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
privatevoid btnLogin_Click(object sender, EventArgs e)
{
//收集用户信息
string name = txtUserName.Text.Trim();
string pwd = txtPwd.Text.Trim();
MODEL.Person per = pm.Login(name);
if (per ==null)
{
MessageBox.Show("登录名不存在");
}
else
{
if (per.PPwd == BLL.CommonHelper.GetPassCode(pwd))//区分大小写
{
MessageBox.Show(per.PCName +":登录成功");
this.DialogResult =DialogResult.OK;
//在winform里面,如果关闭起始窗体,那么就会关闭从起始窗体打开的所有直接或者间接窗体,相当于退出程序
//以ShowDialog()方式打开的窗体,只要你能够给它一个除了none以外的DialogResult值,那么窗体都会关闭
}
else
{
MessageBox.Show("密码错误了");
}
}
}
#endregion
ii. 业务层代码
#region登录验证 +MODEL.Person Login(string name)
///<summary>
///登录验证
///</summary>
///<param name="name"></param>
///<returns></returns>
public MODEL.Person Login(string name)
{
return ps.Login(name);
}
#endregion
iii. 数据访问层代码
#region登录验证 +MODEL.Person Login(string name)
///<summary>
///登录验证
///</summary>
///<param name="name"></param>
///<returns></returns>
public MODEL.Person Login(string name,bool isValidate=true)
{
string sql ="select pid,pcid,ptype,ploginname,pcname,ppyname,ppwd,pgender,pemail,pareas,pisdel,paddtime from person where ploginname=@name ";
if(isValidate)
{
sql += " and pisdel=0";
}
SqlParameter p =newSqlParameter("name", name);
MODEL.Person per =null;
using (SqlDataReader reader =SqlHelper.ExecuteReader(sql, p))//当使用完数据读取器做释放之后,也自动释放与之关联的连接通道
{
if (reader.Read())//说明有数据,但是就算有也只有一行数据,所以不需要循环
{
per = new MODEL.Person();
per.PID = (int)reader["PID"];
per.PCID = (int)reader["PCID"];
if (!(reader["PType"]isDBNull))
{
per.PType = (int)reader["PType"];
}
//数据库的值读取到c#之后,如果是数据就被封装为object类型,如果是null就被封装为DBNull,任意的类型都可以ToString(),但是如果是数据表中可以为null的值需要转换为string之外的类型,就需要做DBNull的判断
per.PLoginName = reader["PLoginName"].ToString();
per.PCName = reader["PCName"].ToString();
per.PPwd = reader["PPwd"].ToString();
per.PPYName = reader["PPYName"].ToString();
per.PEmail = reader["PEmail"].ToString();
per.PAreas = reader["PAreas"].ToString();
per.PGender = (bool)reader["PGender"];
per.PIsDel = (bool)reader["PIsDel"];
per.PAddTime = Convert.ToDateTime(reader["PAddTime"]);
}
}
return per;
}
#endregion
iv. 关闭登录窗体,打开主窗体代码(program.cs中)
staticvoid Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
FrmLogin frm =newFrmLogin();
//以ShowDialog方式打开的窗体,只需要赋值一个DialogResult值,窗体就会关闭(不能是none, 如果是点击右上角的x那么默认返回Cancel)
DialogResult re= frm.ShowDialog();
if (re ==DialogResult.OK)
{
//这才是起始窗体
Application.Run(newFrmMain());
}
}
2. 打开主窗体界面:
a) 界面:
b) 常用属性:
3. 打开子窗体(人员管理窗体和班级管理窗体)
a) 在MDI父容器中打开MDI子窗体 1.设置父窗体的IsMdiContainer为true,2.设置子窗体的MdiParent为this
#region学员管理窗体+void tsmiStudent_Click(object sender, EventArgs e)
///<summary>
///打开学员管理窗体
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
privatevoid tsmiStudent_Click(object sender, EventArgs e)
{
FrmPerson frm =FrmPerson.GetFrmPerson();
//需要设置打开的窗体的父容器是当前窗体
frm.MdiParent = this;
frm.Show();
}
#endregion
b) 单例模式的使用
i. 私有的构造函数
private FrmPerson()
{
InitializeComponent();
}
ii. 公共的静态方法返回当前窗体实例
///<summary>
///当前窗体对象
///</summary>
staticFrmPerson frm;
#region使用单例模式返回当前窗体对象 +static FrmPerson GetFrmPerson()
///<summary>
///使用单例模式返回当前窗体对象
///</summary>
///<returns></returns>
publicstaticFrmPerson GetFrmPerson()
{
//窗体对象如果关闭了,并没有真正为null.而是被释放的状态
if (frm ==null || frm.IsDisposed)
{
frm = newFrmPerson();
}
return frm;
}
#endregion
4. 人员管理窗体的功能完成:
a) 界面
b) 获取所有人员信息
i. 创建业务层方法,向数据访问层发送请求
#region获取所有人员列表实体类集合 +List<MODEL.Person> GetAllPersonList(bool isdel)
///<summary>
///获取所有人员列表实体类集合
///</summary>
///<param name="isdel">标记是否删除</param>
///<returns></returns>
publicList<MODEL.Person> GetAllPersonList(bool isdel)
{
return ps.GetAllPersonList(isdel);
}
#endregion
ii. SqlHelper中封装获取结果集的方法
#region获取查询结果集 +DataTable ExecuteTable(string sql, params SqlParameter[] ps)
///<summary>
///获取查询结果集
///</summary>
///<param name="sql">查询命令</param>
///<param name="ps">查询参数</param>
///<returns></returns>
publicstaticDataTable ExecuteTable(string sql, paramsSqlParameter[] ps)
{
SqlDataAdapter da =newSqlDataAdapter(sql,connStr);
da.SelectCommand.Parameters.AddRange(ps);
DataTable dt =newDataTable();
da.Fill(dt);
return dt;
}
#endregion
iii. 数据访问层根据用户的请求进行查询操作,返回数据表后将数据表转换为面向对象的实体类集合,同时将集合返回给业务层
#region获取所有人员列表实体类集合 +List<MODEL.Person> GetAllPersonList(bool isdel)
///<summary>
///获取所有人员列表实体类集合
///</summary>
///<param name="isdel">标记是否删除</param>
///<returns></returns>
publicList<MODEL.Person> GetAllPersonList(bool isdel)
{
string sql ="select pid,pcid,Classes.CName,ptype,ploginname,pcname,ppyname,ppwd,pgender,pemail,pareas,pisdel,paddtime from person inner join Classes on Person.PCID=Classes.CID where pisdel=@isdel ";
SqlParameter p =newSqlParameter("isdel",isdel);
DataTable dt =SqlHelper.ExecuteTable(sql, p);
return GetList(dt);
}
#endregion
#region通过Person数据表返回Person实体类集合 + List<MODEL.Person> GetList(DataTable dt)
///<summary>
///通过Person数据表返回Person实体类集合
///</summary>
///<param name="dt"></param>
///<returns></returns>
List<MODEL.Person> GetList(DataTable dt)
{
List<MODEL.Person> lists =null;
if (dt.Rows.Count > 0)//说明表中查询到的数据行,那么就需要实体化存储数据行对象的集合
{
lists = newList<MODEL.Person>();
//循环遍历表的每一行数据
foreach (DataRow rowin dt.Rows)
{
//每一行数据就对应着一个对象
MODEL.Person temp =new MODEL.Person();
GetPeronObject(row, temp);
//将生成的对象添加到集合中
lists.Add(temp);
}
}
return lists;
}
#endregion
#region通过Person数据行转换为Person实体类对象 + void GetPeronObject(DataRow row, MODEL.Person per)
///<summary>
///通过Person数据行转换为Person实体类对象
///</summary>
///<param name="row"></param>
///<param name="per"></param>
void GetPeronObject(DataRow row, MODEL.Person per)
{
per.PID = (int)row["PID"];
per.PCID = (int)row["PCID"];
per.PType = (int)row["PType"];
per.PLoginName = row["PLoginName"].ToString();
per.PCName = row["PCName"].ToString();
per.PPwd = row["PPwd"].ToString();
per.PPYName = row["PPYName"].ToString();
per.PEmail = row["PEmail"].ToString();
per.PAreas = row["PAreas"].ToString();
per.PGender = (bool)row["PGender"];
per.PIsDel = (bool)row["PIsDel"];
per.PAddTime = Convert.ToDateTime(row["PAddTime"]);
per.CName=row["CName"].ToString();
}
#endregion
iv. 业务层将数据访问层返回的集合返回给UI层
v. UI层进行DataGridView控件的数据绑定。
this.dgvList.DataSource = pm.GetAllPersonList(false);
vi. DataGridView列集合的绑定属性说明:
vii. 设置DataGridView控件的列集合绑定属性
viii. 设置DataGirdView的不自动生成列属性
//没有在Columns集合中绑定的列不会自动生成
this.dgvList.AutoGenerateColumns =false;
ix. 修改实体类,修改DataGridView控件列的数据显示方式
///<summary>
///人员类型(1-学生,2-老师)
///</summary>
publicint PType
{
set { _ptype =value; }
get {return _ptype; }
}
publicstring PTypeString
{
set { _ptype =value =="学生"?1:2; }
get {return _ptype == 1 ?"学生" :"老师"; }
}
///<summary>
///性别
///</summary>
publicbool PGender
{
set { _pgender =value; }
get {return _pgender; }
}
publicstring PGenderString
{
set { PGender =value =="男" ?true :false; }
get {return PGender ?"男" :"女"; }
}
c) 新增人员信息
i. 显示新增人员信息面板
ii. 加载班级列表数据
1. 创建班级表实体类
publicclassClasses
{
public Classes()
{ }
#region Model
privateint _cid;
privatestring _cname;
///<summary>
///班级表ID
///</summary>
publicint CID
{
set { _cid =value; }
get {return _cid; }
}
///<summary>
///班级名称
///</summary>
publicstring CName
{
set { _cname =value; }
get {return _cname; }
}
#endregion Model
}
2. 创建班级表业务层处理类,向数据访问层发送请求
#region获取所有班级列表 +List<MODEL.Classes> GetClassesList(bool isdel)
///<summary>
///获取所有班级列表
///</summary>
///<param name="isdel">标记是否删除</param>
///<returns></returns>
publicList<MODEL.Classes> GetClassesList()
{
return cs.GetClassesList();
}
#endregion
3. 创建班级表访问层类,添加获取所有班级列表信息方法
#region获取所有班级列表 +List<MODEL.Classes> GetClassesList()
///<summary>
///获取所有班级列表
///</summary>
///<param name="isdel">标记是否删除</param>
///<returns></returns>
publicList<MODEL.Classes> GetClassesList()
{
string sql ="select cid,cname from classes ";
DataTable dt =SqlHelper.ExecuteTable(sql);
List<MODEL.Classes> lists =null;
if(dt.Rows.Count>0)
{
lists = newList<MODEL.Classes>();
foreach (DataRow rowin dt.Rows)
{
//每一行数据就对应着一个实体类对象
MODEL.Classes temp =new MODEL.Classes();
GetClassesObject(row, temp);
//将对象添加到集合
lists.Add(temp);
}
}
return lists;
}
#endregion
4. 将班级表数据转换为班级实体类集合,同时返回给业务层
#region将Classes数据行转换为Classes实体类对象 +void GetClassesObject(DataRow row, MODEL.Classes cla)
///<summary>
///将Classes数据行转换为Classes实体类对象
///</summary>
///<param name="row"></param>
///<param name="cla"></param>
void GetClassesObject(DataRow row, MODEL.Classes cla)
{
cla.CID = (int)row["CID"];
cla.CName = row["CName"].ToString();
}
#endregion
5. 业务层将班级实体类集合返回给UI层,做下拉列表的数据绑定。
privatevoid FrmPerson_Load(object sender, EventArgs e)
{
//绑定班级下拉列表数据.在load里面创建是为了避免每一次新增人员时反复加载班级列表数据
this.cboClasses.DisplayMember ="CName";
this.cboClasses.ValueMember ="CID";
this.cboClasses.DataSource = cm.GetClassesList(false);
}
iii. 加载地区信息
1. 创建地区表实体类
publicclassAreas
{
public Areas()
{ }
#region Model
privateint _aid;
privatestring _aname;
privateint _apid;
///<summary>
///
///</summary>
publicint AID
{
set { _aid =value; }
get {return _aid; }
}
///<summary>
///
///</summary>
publicstring AName
{
set { _aname =value; }
get {return _aname; }
}
///<summary>
///父级节点ID(-1为顶级节点)
///</summary>
publicint APid
{
set { _apid =value; }
get {return _apid; }
}
#endregion Model
}
2. 创建地区表业务逻辑层类,向地区表数据访问层发送请求
List<MODEL.Areas> lists = null;
#region获取地区集合 +List<MODEL.Areas> GetAreasList(bool isdel)
///<summary>
///获取地区集合
///</summary>
///<param name="isdel"></param>
///<returns></returns>
publicList<MODEL.Areas> GetAreasList()
{
lists=new DAL.AreasService().GetAreasList();
return lists;
}
#endregion
3. 创建地区表数据访问层类,添加获取所有地区表的方法
#region获取地区集合 +List<MODEL.Areas> GetAreasList(bool isdel)
///<summary>
///获取地区集合
///</summary>
///<param name="isdel"></param>
///<returns></returns>
publicList<MODEL.Areas> GetAreasList()
{
string sql ="select aid,aname,apid from areas";
DataTable dt =SqlHelper.ExecuteTable(sql,p);
List<MODEL.Areas> lists =null;
if(dt.Rows.Count>0)
{
lists = newList<MODEL.Areas>();
foreach (DataRow rowin dt.Rows)
{
MODEL.Areas temp =new MODEL.Areas();
GetAreasObject(row, temp);
lists.Add(temp);
}
}
return lists;
}
#endregion
4. 将地区表数据转换为地区实体类集合,返回给业务层
#region将Areas数据行转换为Areas实体类对象 void GetAreasObject(DataRow row, MODEL.Areas area)
///<summary>
///将Areas数据行转换为Areas实体类对象
///</summary>
///<param name="row"></param>
///<param name="area"></param>
void GetAreasObject(DataRow row, MODEL.Areas area)
{
area.AID = (int)row["AID"];
area.APid = (int)row["APid"];
area.AName = row["AName"].ToString();
}
#endregion
5. 业务层将集合返回给UI层,UI层进行树控件数据的添加
#region使用递归加载地区信息 +void LoadData(int id, TreeNode parentNode)
///<summary>
///使用递归加载地区信息
/// 1.递归调用方法本身
/// 2.递归可以结束,不是死循环
///</summary>
///<param name="id"></param>
///<param name="parentNode"></param>
void LoadData(int id,TreeNode parentNode)
{
for (int i = 0; i < lists.Count;i++ )
{
if (lists[i].APid == id)//加载省节点
{
TreeNode node =newTreeNode(lists[i].AName);
//将当前地区对象存储到树节点的Tag值中
node.Tag = lists[i];
if (parentNode ==null)//第一次添加节点,添加给树控件
{
//将节点添加到树控件中
tvlist.Nodes.Add(node);
}
else
{
parentNode.Nodes.Add(node);
}
lists.RemoveAt(i);//移除已经添加的节点所对应的对象
i--;
//方法调用方法本身
LoadData((node.Tag as MODEL.Areas).AID, node);
}
}
}
#endregion
6. 获取用户选择的地区信息值:
#region选择地区 +void btnOk_Click(object sender, EventArgs e)
///<summary>
/// 选择地区
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
privatevoid btnOk_Click(object sender, EventArgs e)
{
TreeNode node =this.tvlist.SelectedNode;
if (node ==null)
{
return;
}
String path=node.FullPath;
}
#endregion
7. 修改打开地区选择窗体代码,传入FrmPerson窗体对象
#region打开地区选择窗体 void btnChoice_Click(object sender, EventArgs e)
///<summary>
///打开地区选择窗体
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
privatevoid btnChoice_Click(object sender, EventArgs e)
{
FrmAreas frm =newFrmAreas(this);
frm.ShowDialog();
}
#endregion
1. 在FrmPerson中添加填充地区信息值的方法
#region填充地区信息到文本框控件 +void GetAreas(string aname)
///<summary>
///填充地区信息到文本框控件
///</summary>
///<param name="aname"></param>
publicvoid GetAreas(string aname)
{
txtDistrict.Text = aname;
}
#endregion
2. 在privatevoid btnOk_Click(object sender, EventArgs e)中添加代码,填充地区值,同时关闭选择地区窗体
frm.GetAreas(SBAname.ToString().Substring(0,SBAname.Length-1)
this.DialogResult =DialogResult.OK;
iv. 进行用户数据的输入验证
1. 使用正则表达式进行用户输入值合法性验证
#region用户输入验证 + bool ValidateInput()
///<summary>
///用户输入验证
/// 1.从用户输入的值的合法性进行判断--正则表达式
/// 2.是将用户输入值从数据层面进行判断(在服务器端判断)--进行数据库查询
///</summary>
///<returns></returns>
bool ValidateInput()
{
if (string.IsNullOrEmpty(txtName.Text.Trim()) ||Regex.IsMatch(txtName.Text.Trim(),@"\W"))
{
MessageBox.Show("请输入合法的用户名");
//获取焦点
txtName.Focus();
txtName.SelectAll();//选择文本
returnfalse;
}
if (string.IsNullOrEmpty(txtLoginName.Text.Trim()) ||Regex.IsMatch(txtLoginName.Text.Trim(),@"\W"))
{
MessageBox.Show("请输入合法的登录名");
//获取焦点
txtLoginName.Focus();
txtLoginName.SelectAll();//选择文本
returnfalse;
}
if (string.IsNullOrEmpty(txtPwd.Text.Trim()) || txtPwd2.Text.Trim()!=txtPwd.Text.Trim())
{
MessageBox.Show("请输入再次一致的密码");
//获取焦点
txtPwd2.Focus();
txtPwd2.SelectAll();//选择文本
returnfalse;
}
//可以为null的字段值在输入值之后才需要进行验证
if(!string.IsNullOrEmpty(txtEmail.Text.Trim()))
{
if(!Regex.IsMatch(txtEmail.Text.Trim(),@"^\w+[@]\w+[.]\w+$"))
{
MessageBox.Show("请输入正确的电子邮箱");
txtEmail.Focus();
returnfalse;
}
}
returntrue;
}
#endregion
2. 进行登录名是否重复的服务器端数据合法性验证
#region登录名是否重复的合法性验证 +void txtLoginName_Leave(object sender, EventArgs e)
///<summary>
///登录名是否重复的合法性验证
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
privatevoid txtLoginName_Leave(object sender, EventArgs e)
{
//判断如果是点击取消或者关闭当前窗体就不用再做登录名是否重复的判断 ActiveControl是指窗体当前激活控件
// 点击关闭点击的按钮同时是取消按钮
if (this.ActiveControl == null || (this.ActiveControlisButton && ((Button)this.ActiveControl).Name == "btnCancel"))
{
return;
}
if (string.IsNullOrEmpty(txtLoginName.Text.Trim()) || Regex.IsMatch(txtLoginName.Text.Trim(),@"\W"))
{
MessageBox.Show("请输入合法的登录名");
//获取焦点
txtLoginName.Focus();
txtLoginName.SelectAll();//选择文本
return;
}
string loginname = txtLoginName.Text.Trim();
MODEL.Person per = pm.Login(loginname,false);
if (per !=null)
{
MessageBox.Show("登录名已经存在,请重新输入");
//获取焦点
txtLoginName.Focus();
}
}
#endregion
v. 收集面板数据,封装在Person实体类对象中,调用业务层方法进行新增操作
MODEL.Person newPerson =new MODEL.Person();
newPerson.PCID = (int)cboClasses.SelectedValue;
//newPerson.PType = cboIdentity.Text == "学生" ? 1 : 2;
newPerson.PType = cboIdentity.SelectedIndex + 1;
newPerson.PLoginName = txtLoginName.Text.Trim();
newPerson.PCName = txtName.Text.Trim();
newPerson.PPYName ="";//搞不定,以后再说
newPerson.PPwd = txtPwd2.Text.Trim();
newPerson.PGender = rdoMale.Checked ?true :false;
newPerson.PEmail = txtEmail.Text.Trim();
newPerson.PAreas = txtDistrict.Text;
if (pm.AddPerson(newPerson)== 1)
{
MessageBox.Show(gpAdd.Text+"成功");
ClearPanel();
this.gpAdd.Visible =false;
this.dgvList.DataSource = pm.GetAllPersonList(false);
}
else
{
MessageBox.Show("新增失败");
}
vi. 在Person表业务层调用方法获取拼音的方法获取姓名的拼音
per.PPYName =SpellCodeHelper.GetAllPYLetters(per.PCName);
vii. 在Person表业层添加密码加密的方法
#region使用web命名空间中的类实现MD5加密 static string GetPassCode(string pwd)
///<summary>
///使用web命名空间中的类实现MD5加密
///</summary>
///<returns></returns>
publicstaticstring GetPassCode(string pwd)
{
//第一个参数是指你需要那一个字符串进行加密,第二个参数是指定使用那一个“加密”算法
return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(pwd,"md5");
}
#endregion
viii. 在Person业务逻辑层创建新增人员信息方法,将用户请求传递给数据访问层进行处理
#region新增人员信息 +int AddPerson(MODEL.Person per)
///<summary>
///新增人员信息
///</summary>
///<param name="per"></param>
///<returns></returns>
publicint AddPerson(MODEL.Person per)
{
//获取当前用户的姓名拼音
per.PPYName = SpellCodeHelper.GetAllPYLetters(per.PCName);
//对密码进行MD5“加密"
per.PPwd = CommonHelper.GetPassCode(per.PPwd);
return ps.AddPerson(per);
}
#endregion
ix. 在SqlHelper中封装增加删除和修改的公共方法,返回受影响行数
#region执行增加删除和修改操作 +static int ExecuteNonQuery(string sql, params SqlParameter[] ps)
///<summary>
///执行增加删除和修改操作
///</summary>
///<param name="sql">增加删除修改命令</param>
///<param name="ps">参数</param>
///<returns>受影响的行数</returns>
publicstaticint ExecuteNonQuery(string sql, paramsSqlParameter[] ps)
{
using(SqlConnection conn=newSqlConnection(connStr))
{
conn.Open();
SqlCommand comm =newSqlCommand(sql,conn);
comm.Parameters.AddRange(ps);
return comm.ExecuteNonQuery();
}
}
#endregion
x. 在Person数据访问层类中创建新增人员方法,调用公共方法进行新增操作,返回受影响行数
#region新增人员信息 +int AddPerson(MODEL.Person per)
///<summary>
///新增人员信息
///</summary>
///<param name="per"></param>
///<returns></returns>
publicint AddPerson(MODEL.Person per)
{
//不要去判断用户到底有没有输入某个值,而是插入所有数据
string sql ="insert into person values(@pcid,@ptype,@ploginname,@pcname,@ppyname,@ppwd,@pgender,@pemail,@pareas,default,default)";
SqlParameter[] ps = {
newSqlParameter("pcid",per.PCID),
newSqlParameter("ptype",per.PType),
newSqlParameter("ploginname",per.PLoginName),
newSqlParameter("pcname",per.PCName),
newSqlParameter("ppyname",string.IsNullOrEmpty(per.PPYName)?DBNull.Value:(object)per.PPYName),
newSqlParameter("ppwd",per.PPwd),
newSqlParameter("pgender",per.PGender),
newSqlParameter("pemail",string.IsNullOrEmpty(per.PEmail)?DBNull.Value:(object)per.PEmail),
newSqlParameter("pareas",string.IsNullOrEmpty(per.PAreas)?DBNull.Value:(object)per.PAreas)
};
returnSqlHelper.ExecuteNonQuery(sql, ps);
}
#endregion
xi. 业务层将受影响行数据返回给UI层,做出相应的提示。