一、基本组成
- 创建一个空解决方案,在解决方案中创建四个项目:窗体项目UI、类库项目DAL、BBL、Model;
- 导入必备文件:UI(app.config、引用BBL和Model),DAL(导入SqlHelper、引用system.configuration),BBL(引用DAL);
- 为什么app.config文件要放在UI层?因为所有的dll文件最后执行时都要放到UI层,而DAL层的sqlhelper在执行时也是在UI层,所以sqlhelper找app.config也是在UI层中找,如果将app.config放到其他层,则无法找到;
二、编写步骤
- 根据需求确定SQL语句;
- 根据sql语句编写数据访问层代码(如果传入的参数多,则应在Model层中创建一个实体类);
- 编写业务逻辑层代码;
- 编写UI层代码;
三、各层编写规范
- 与sql和ADO.NET相关的代码只能在DAL层中编写,如果返回值多,可以封装在list中返回给BBL层;
- BBL层不能出现与sql操作相关的代码,也不能有与UI层控件有关的代码,只关注具体的业务逻辑;
- UI不能和DAL层直接交互;
四、项目总结
1、用户表的增删改查
具体代码不再复制过来,去项目中看
项目要点:
- 对空值的处理
- 因为三目表达式的:两边的数据类型要一致,所以要进行强制类型转换。具体规则:向数据库中插入数据,不管数据库中是什么类型一律强转为object;给实体类赋值时,实体类中是什么类型就强转为什么类型;
各层核心代码
- Model—person
此处?表示可以为空,可以给变量赋值null``
// 此处?表示可以为空
public int? height { get; set; }
public bool? gender { get; set; }
- DAL
向数据库中输入,不管数据库中是什么类型一律强转为object;
new SqlParameter("@height",System.Data.SqlDbType.Int){
Value = (p.height == null?DBNull.Value:(object)p.height)}
判断数据库中某个字段是否为空 reader.IsDBNull(index);
p.height = reader.IsDBNull(3)?null:(int?)reader.GetInt32(3);
获取数据库中bit(bool)类型的gender
p.gender = reader.IsDBNull(4) ? null : (bool?)reader.GetBoolean(4);
- UI
通过长度来判断是否为空
(int?) 要进行强制转换,不然会报错;给实体类赋值时,实体类中是什么类型就强转为什么类型
p.height = textBox3.Text.Trim().Length == 0 ? null : (int?)int.Parse(textBox3.Text.Trim());
数据绑定应该独立封装成一个方法,crud后都要调用;
private void LoadData()
{
// 给dataGridView1绑定数据源
dataGridView1.DataSource = bbl.Select();
}
dataGridView中的CellFormatting事件,用来修改显示的内容;
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if(e.ColumnIndex == 4 && e.Value != null)
{
e.Value = (bool)e.Value == true ? "男" : "女";
}
}
删除时如何获得选中行的id:在rowenter事件中将当前行id的值赋给一个lable即可
// 将选中行的数据加载到页面上
private void dataGridView1_RowEnter(object sender, DataGridViewCellEventArgs e)
{
// 获取被选中行的索引
int index = e.RowIndex;
// 获取被选中行的数据
DataGridViewRow data = dataGridView1.Rows[index];
// 将被选中行转换成person对象
Person s = data.DataBoundItem as Person;
if (s != null)
{
textBox5.Text = s.name;
textBox6.Text = s.age.ToString();
textBox7.Text = s.height == null ? string.Empty : s.height.ToString();
comboBox2.SelectedIndex = s.gender == null ? 0 : s.gender == true ? 1 : 2;
// 使用lable来存放当前行的id用于删除、修改
label9.Text = s.id.ToString();
}
}
2、contacts增删改查
项目要点:
-
contacts表中存在外键如何处理?
1.外键所在的表建立一个实体类,在contacts实体类中创建外键实体类的属性(是整个实体类的而不是其中的某个字段);
2.在UI层给contact表中的外键赋值时,首先要new一个外键实体类的新对象,然后再给其中的属性赋值; -
如何根据外键id找出对应的名称:两表进行内连接;
-
combobox同源同步
1.定义:如果两个combobox控件绑定的数据源相同,那么改变其中一个的内容,另外一个也会同步改变;
2.解决方法:调用list的ToList()方法,生成一个新的list;
5、单例模式
public partial class Form3 : Form
{
// 单例模式三步走
// 1、构造函数私有化
private Form3()
{
InitializeComponent();
}
// 2、创建私有静态字段
private static Form3 form3;
// 3、 创建公有静态方法判断
public static Form3 GetForm3()
{
// isDisposed解决关闭窗体后打不开的问题
if(form3==null || form3.IsDisposed)
{
form3 = new Form3();
}
return form3;
}
}