什么是七层?
其实七层也并没有那么复杂,无非在三层的基础上多扩展了三层而已。
1. UI层:接收用户输入的数据,向用户展示要输出的信息
2. Facade(外观层): 运用外观模式,提供 B 层的入口,降低 U 层和 B 层的耦合
3. BLL层: 从 U 层中获取用户指令和数据,执行业务逻辑
4. Factory(工厂层):返回一个 D 层对象。在工厂层中利用了反射,可以很方便的更换 D 层。
5. IDAL(数据接口层):抽象了数据层中的方法,D层继承 IDAL 层。我认为它的意义所在就是更换 D 层时,直接创建类实现接口,以期可以很方便的和原来的 D 层保持一致。B 层可以通过接口调用具体的 D 层方法,正是利用了反射+多态才实现了数据库的易更换。
6. DAL层:和数据源打交道,执行数据库的一些操作。
7. Entity层:封装了信息,通过实体层的具体对象在各个层之间传递数据
通过七层和三层的比较,发现七层无非就是比三层多加了三层,而这三层的作用就是降低原来三层之间的耦合,可以更加灵活的扩展和修改。
包图
代码展示
Entity层
public class UserInfo
{
public Int64 userID { set; get; }
public string userName { set; get; }
public string password { set; get; }
//用户等级
public string level { set; get; }
//此用户的开户人
public Int64 registrantID { set; get; }
}
IDAL层
public interface IUserInfoDAL
{
DataTable SelectUser(Entity.UserInfo userinfo);
}
DAL层
public class SQLHelper
{
private SqlConnection conn = null;
private SqlCommand cmd = null;
private SqlDataReader sdr = null;
public SQLHelper()
{
string connStr = ConfigurationManager.AppSettings["ConnStr"];
conn = new SqlConnection(connStr);
}
/// <summary>
/// 打开数据库连接
/// </summary>
/// <returns></returns>
private SqlConnection GetConn()
{
if (conn.State == ConnectionState.Closed)
{
conn.Open();
}
return conn;
}
/// <summary>
/// 执行不带参数的增删改SQL语句或存储过程
/// </summary>
/// <param name="cmdText">SQL语句或存储过程名</param>
/// <param name="ct">执行的命令类型</param>
/// <returns>受影响的行数</returns>
public int ExecuteNonQuery(string cmdText, CommandType ct)
{
//受影响的行数
int res;
using (cmd = new SqlCommand(cmdText, GetConn()))
{
cmd.CommandType = ct;
res = cmd.ExecuteNonQuery();
}
return res;
}
/// <summary>
/// 执行带参数的增删改SQL语句或存储过程
/// </summary>
/// <param name="cmdText">SQL语句或者存储过程名</param>
/// <param name="paras">SqlCommand参数集合</param>
/// <param name="ct">执行的命令类型</param>
/// <returns></returns>
public int ExecuteNonQuery(string cmdText, SqlParameter[] paras, CommandType ct)
{
int res;
using (cmd = new SqlCommand(cmdText, GetConn()))
{
cmd.CommandType = ct;
cmd.Parameters.AddRange(paras);
res = cmd.ExecuteNonQuery();
}
return res;
}
/// <summary>
/// 执行不带参数的查询SQL语句或存储过程
/// </summary>
/// <param name="cmdText">查询SQL语句或存储过程</param>
/// <param name="ct">执行的命令类型</param>
/// <returns></returns>
public DataTable ExecuteQuery(string cmdText,CommandType ct)
{
DataTable dt = new DataTable();
cmd = new SqlCommand(cmdText, GetConn());
cmd.CommandType = ct;
//CommandBehavior.CloseConnection的作用是dataReader关闭时其所对应的数据库连接也关闭
using (sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
dt.Load(sdr);
}
return dt;
}
/// <summary>
/// 执行带参数的SQL语句或存储过程
/// </summary>
/// <param name="cmdText">查询SQL语句或存储过程名</param>
/// <param name="paras">参数集合</param>
/// <param name="ct">执行的命令类型</param>
/// <returns></returns>
public DataTable ExecuteQuery(string cmdText,SqlParameter[] paras,CommandType ct)
{
DataTable dt = new DataTable();
cmd = new SqlCommand(cmdText, GetConn());
cmd.CommandType = ct;
cmd.Parameters.AddRange(paras);
using (sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
dt.Load(sdr);
}
return dt;
}
}
public class SqlUserInfoDAL : IDAL.IUserInfoDAL
{
public DataTable SelectUser(UserInfo userinfo)
{
SQLHelper sqlHelper = new SQLHelper();
string sql = "select * from User_Info where UserID=@userID and PWD = @password";
SqlParameter[] paras = {new SqlParameter("@userID",userinfo.userID),
new SqlParameter("@password",userinfo.password)};
return sqlHelper.ExecuteQuery(sql,paras, CommandType.Text);
}
}
Factory层
public class Factory
{
//读取配置文件中所用数据库名称
private static string strDB = System.Configuration.ConfigurationManager.AppSettings["DB"];
//程序集名称
private static string assemblyName = strDB + "DAL";
public static IDAL.IUserInfoDAL CreateUserInfoDAL()
{
//要创建的类名
string className = assemblyName + "." + strDB + "UserInfoDAL";
return (IDAL.IUserInfoDAL)Assembly.Load(assemblyName).CreateInstance(className);
}
}
BLL层
public class LoginBLL
{
public bool SelectUser(Entity.UserInfo userInfo)
{
IDAL.IUserInfoDAL login = Factory.Factory.CreateUserInfoDAL();
//B层调D层
DataTable dt = login.SelectUser(userInfo);
bool flag;
//DataTable的总行数是0,则说明没有这个用户
if (dt.Rows.Count == 0)
{
flag = false;
}
else
{
flag = true;
}
return flag;
}
}
Facade层
public class LoginFacade
{
public Boolean SelectUser(Entity.UserInfo userInfo)
{
return new BLL.LoginBLL().SelectUser(userInfo);
}
}
UI层
public partial class frmLogin : Form
{
public frmLogin()
{
InitializeComponent();
}
private void btnLogin_Click(object sender, EventArgs e)
{
//判断输入不能为空
if (txtUserID.Text.Trim() == "")
{
MessageBox.Show("请填写账号!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
if (txtPWD.Text == "")
{
MessageBox.Show("请填写密码!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
try
{
Entity.UserInfo userInfo = new Entity.UserInfo();
userInfo.userID = Convert.ToInt64(txtUserID.Text.Trim());
userInfo.password = txtPWD.Text;
Boolean flag = false;
Facade.LoginFacade loginFacade = new Facade.LoginFacade();
flag = loginFacade.SelectUser(userInfo);
if (flag != false)
{
this.Hide();
MessageBox.Show("登录成功!", "恭喜",MessageBoxButtons.OK);
}
else
{
MessageBox.Show("账号或者密码错误!");
}
}
catch (Exception)
{
throw;
}
}
}
错误解决
在敲完之后需要执行的时候,可能会报以下两种错误:
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/277f37029f2b8c59f9e5c3cabe6796c7.png)
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/dd1e6656d0f4c272ee1122e7444a2cc0.png)
以下提供三种解决方法:
①手动将 DAL 层生成的.dll文件拷贝到 UI 层的Debug文件夹中。
②更改 DAL 层编译后文件的生成路径
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/0b917ee7c0fe4df61a702d3844e63dfc.png)
③修改 Factory 层中的代码
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/b812b09c21f4a7221ea3adaf43f30ae2.png)