一.精简三层架构DAL认识
之前都是直接在界面(UI)中写SQL,对于大的项目这样做很难维护,而且复用性不强,三层架构是企业开发中常用的设计模式,把数据库访问,业务逻辑,界面分离。
初学者直接学习三层架构会比较难,因此这次用精简的三层架构,只用DAL(Data Access Layer)层,把数据库访问封装到DAL中,UI调用DAL,原则“UI中不出现SQL”
二.精简版DAL的学习
创建StudentDAL类,用于实现数据访问
1.没有参数:如查询数据库中对应表的总条数,在UI层,只需要调用StudentDAL类中的对应方法就可以,不用写任何有关的SQL语句
UI层:(.cs)
private void button1_Click(object sender, RoutedEventArgs e)
{
int count=StudentDAL.GetCount();
MessageBox.Show(count.ToString());
}
DAL层:(StudentDAL.cs)
/// <summary>
/// 获取数据总条数
/// </summary>
/// <returns></returns>
public static int GetCount()
{
return (int)SqlHelper.ExecuteScalar("select count(*) from T_Student");
}
2.少量参数(如一个),如删除编号为3的学生,同上,在 UI层,只需要调用StudentDAL类中的对应方法就可以了,不用写任何有关数据访问的SQL语句,只要把对应的少量参数传递就可以
UI层:(.cs)
private void button2_Click(object sender, RoutedEventArgs e)
{
StudentDAL.DelStudentById(3);
MessageBox.Show("删除成功!");
}
DAL层:(StudentDAL.cs)
/// <summary>
/// 通过编号删除数据
/// </summary>
/// <param name="id"></param>
public static void DelStudentById(long id)
{
SqlHelper.ExecuteNonQuery("delete from T_Student where Id=@id", new SqlParameter("@id", id));
}
3.大量参数操作,如需要向数据库中添加一个学生的信息,字段量非常大,并且有可空,有不可空的情况,处理起来再按照如上的参数一个一个写是非常费时费事的,这样就需要引入一个新的概念Model(我把它暂时理解为对象类),直接传对象
写一个Student类:
namespace 初学三层架构DAL精简版
{
//在构建Student Model时候切记要与数据库保持一致,并且数据库中可空的,在Model中要有标识
//建Model的好处是:在插入一个学生,添加的参数会很多,可是把这许多参数都放在Student类中,
//添加一个对象就可以了,存取非常方便,打点就能实现
class Student
{
public long Id { get; set; }//数据空中这个字段是bigint类型,对应C#中的long类型
public string StudentName { get; set; }
public int StudentAge { get; set; }
public string StudentTel { get; set; }
public string StudentAddress { get; set; }//这个字段可为空,但是它是string类型的,
//本身就是可空类型,所以不用加?加了反而会出错
public DateTime? StudentBirthday { get; set; }//这个字段可为空,它是DataTime类型,
//如同int ,bool ,decimal类型不能为空,要加?,变为可空类型
}
}
现在考虑一个问题:如果项目中对于有些字段没有要求,可空传递,如何解决?
如以下情况,学生地址,和学生出生日期可以为空,但是作为Student对象的属性,参数传递到DAL层,DAL层对应的插入方法是找不到参数的,这里必须要将null转换成DBNull.Value
UI层(.cs)
private void button3_Click(object sender, RoutedEventArgs e)
{
Student student = new Student();
student.StudentName = "张三";
student.StudentAge = 22;
student.StudentTel = "13523659529";
//student.StudentAddress = "南阳";
//student.StudentBirthday = DateTime.Now;
StudentDAL.InsertStudent(student);
MessageBox.Show("添加成功!");
}
DAL层:(StudentDAL.cs)
/// <summary>
/// 添加一条数据
/// </summary>
/// <param name="student"></param>
public static void InsertStudent(Student student)
{
//object StudentBirthday;
//if (student.StudentBirthday == null)
//{
// StudentBirthday = DBNull.Value;
//}
//else
//{
// StudentBirthday = student.StudentBirthday;
//}
SqlHelper.ExecuteNonQuery(@"insert into T_Student(StudentName,StudentAge,StudentTel,StudentAddress,StudentBirthday)
values(@StudentName,@StudentAge,@StudentTel,@StudentAddress,@StudentBirthday)",
new SqlParameter("@StudentName",student.StudentName),
new SqlParameter("@StudentAge",student.StudentAge),
new SqlParameter("@StudentTel",student.StudentTel),
new SqlParameter("@StudentAddress", ToDBValue(student.StudentAddress)),//所有可空字段都要经过转换,
//才能正确存储数据库
new SqlParameter("@StudentBirthday",ToDBValue(student.StudentBirthday)));
}
写一个从null转换为DBNull.Value的方法:
/// <summary>
/// ToDBValue方法,将空字段,转换为DBNull.Value传入数据库中
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static object ToDBValue(object value)
{
if (value == null)
{
return DBNull.Value;
}
else
{
return value;
}
}
4.大量参数操作,从数据库中读取数据,这部分主要考虑一个问题:数据库中Null不知道如何转换为项目中的null,还需要通过DBNull.Value
UI层:(.cs)
private void button4_Click(object sender, RoutedEventArgs e)
{
StudentDAL.GetStudentById(4);
}
DAL层:(StudentDAL.cs)
/// <summary>
/// 通过编号获取学生信息
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public static Student GetStudentById(long id)
{
DataTable dt=SqlHelper.ExecuteDataTable("select * from T_Student where Id=@id",new SqlParameter("@id",id));
if(dt.Rows.Count<=0)
{
return null;
}
else if(dt.Rows.Count>1)
{
throw new Exception("学生重复!");
}
else
{
Student student = new Student();
student.StudentName=(string)dt.Rows[0]["StudentName"];
student.StudentAge=(int)dt.Rows[0]["StudentAge"];
student.StudentTel=(string)dt.Rows[0]["StudentTel"];
student.StudentAddress=(string)FromDBValue(dt.Rows[0]["StudentAddress"]);
student.StudentBirthday = (DateTime?)FromDBValue(dt.Rows[0]["StudentBirthday"]);
//好好研究这行代码,从数据库中获取的可能为DBNull.Value,经过FromDBValue方法反向转换,可能为空,
//但是不能直接再类型转换为DataTime类型,因为DataTime类型为不可空类型,所有要转换为DataTime?类型
return student;
}
}
写一个从DBNull.Value转换为null的方法:
/// <summary>
/// 反向转换,如果value这个数据库中的值为DBNull.Value,则转换为null
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static object FromDBValue(object value)
{
if (value == DBNull.Value)
{
return null;
}
else
{
return value;
}
}
三.总结DBNull.Value
DBNull与数据库中的Null(不知道)是对等的!
Object是所有类的父类,在这里得到了最好的诠释!
目的:项目中的可空字段(null)传入数据库(NULL)
过程:null(用户没有输入)---------Null(数据库不知道),没有值不能传,需要过渡,所有需要了DBNull.Value来解决这个问题,Null(用户没有输入),在插入之前进行判断,如果缺少用户没有输入的参数,就将其转换成DBNull.Value再插入;
目的:数据库中(NULL)传入项目(null)
项目中需要获取数据库中可为空的数据,Null(数据库不知道)------------null(项目中显示为空),同样需要DBNull.Value来解决,在取值之前判断,如果从数据库中获取的值为DBNull.Value,则把要获取的值赋值为null