初学三层结构,写了个代码,大家帮忙看看,顺便给小弟的问题指点一下。谢谢了
数据库中有张用户信息表(UserInfo),功能很简单,就是在页面上显示所有用户信息,和注册用户信息。Web:只有一个Default.aspx页面,负责显示信息,和插入信息。
BLL: UserInfo.cs 负责检查用户在页面的输入和调用DAL的方法。
DAL:SQLHelper.cs 负责查询用户信息和插入新用户的信息到表。
Model:UserEntity.cs 用户实体类。
Web引用:BLL、DAL、Model。
BLL引用:DAL、Model。
DAL引用:Model。
================================================================================================
Web Default.aspx代码
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using BLL;
using Model;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
//调用BLL
UserInfo userInfo = new UserInfo();
GridView1.DataSource = userInfo.GetALLUserInfo();
GridView1.DataBind();
}
}
protected void Button1_Click(object sender, EventArgs e)
{
//调用BLL层
UserInfo userInfo = new UserInfo();
if (!userInfo.CheckUserName(txtUserName.Text))
{
Label1.Text = "用户名过长或为空";
return;
}
if (!userInfo.CheckSex(ddlSex.SelectedValue))
{
Label1.Text = "请选择性别";
return;
}
if (!userInfo.CheckEmail(txtEmail.Text))
{
Label1.Text = "Email地址过长";
return;
}
if (!userInfo.CheckPhone(txtPhone.Text))
{
Label1.Text = "电话号码过长";
return;
}
if (!userInfo.CheckAddress(txtAddress.Text))
{
Label1.Text = "地址过长";
return;
}
if (userInfo.Insert())
{
Label1.Text = "向数据表写入成功";
}
else
{
Label1.Text = "向数据表写入失败";
}
}
}
-----------------------------------------------------
BLL UserInfo.cs代码
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using DAL;
using Model;
namespace BLL
{
public class UserInfo
{
UserEntity userEntity = new UserEntity();
public bool CheckUserName(string UserName)
{
if (UserName.Length > 20 || UserName == "")
{
return false;
}
userEntity.UserName = UserName;
return true;
}
public bool CheckSex(string Sex)
{
userEntity.Sex = Sex;
return true;
}
public bool CheckEmail(string Email)
{
if (Email.Length > 50)
{
return false;
}
userEntity.Email = Email;
return true;
}
public bool CheckPhone(string Phone)
{
if (Phone.Length > 20)
{
return false;
}
userEntity.Phone = Phone;
return true;
}
public bool CheckAddress(string Address)
{
if (Address.Length > 50)
{
return false;
}
userEntity.Address = Address;
return true;
}
public DataSet GetALLUserInfo()
{
SQLHelper sqlHelper = new SQLHelper();
return sqlHelper.GetAllUserInfo();
}
public bool Insert()
{
return new SQLHelper().Insert(userEntity);
}
}
}
-------------------------------------------------
DAL SQLHelper.cs代码
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using Model;
namespace DAL
{
public class SQLHelper
{
public DataSet GetAllUserInfo()
{
string strSQL = "Select * From UserInfo";
SqlConnection con = new SqlConnection("Data Source = (local);Integrated Security = SSPI;Initial Catalog = DBFile;");
SqlDataAdapter da = new SqlDataAdapter(strSQL, con);
DataSet ds = new DataSet();
da.Fill(ds, "UserInfo");
return ds;
}
public bool Insert(UserEntity userEntity)
{
string UserName = userEntity.UserName;
string Sex = userEntity.Sex;
string Email = userEntity.Email;
string Phone = userEntity.Phone;
string Address = userEntity.Address;
string strSQL = "Insert Into UserInfo Values('" + UserName + "','" + Sex + "','" + Email + "','" + Phone + "','" + Address + "')";
SqlConnection con = new SqlConnection("Data Source = (local);Integrated Security = SSPI;Initial Catalog = DBFile;");
SqlCommand com = new SqlCommand(strSQL, con);
try
{
con.Open();
com.ExecuteNonQuery();
return true;
}
catch
{
return false;
}
finally
{
con.Close();
}
}
}
}
-----------------------------------------
Model UserEntity.cs代码
using System;
using System.Collections.Generic;
using System.Text;
namespace Model
{
public class UserEntity
{
private string _UserName;
private string _Sex;
private string _Email;
private string _Phone;
private string _Address;
public UserEntity() { }
public UserEntity(string UserName, string Sex, string Email, string Phone, string Address)
{
this._UserName = UserName;
this._Sex = Sex;
this._Email = Email;
this._Phone = Phone;
this._Address = Address;
}
public string UserName
{
set { _UserName = value; }
get { return _UserName; }
}
public string Sex
{
set { _Sex = value; }
get { return _Sex; }
}
public string Email
{
set { _Email = value; }
get { return _Email; }
}
public string Phone
{
set { _Phone = value; }
get { return _Phone; }
}
public string Address
{
set { _Address = value; }
get { return _Address; }
}
}
}
================================================================
我的问题
一:我这算算三层结构?
二:各个层的引用对吗?有没有多余或缺少的?
三:我看网上很多都用SQLHelper这个名字,我也不知道SQLHelper这里面的内用是不是和我写的这个差不多?
四:听人说用接口创建对象,我不明白,接口是个契约,里面不都是定义的函数吗,怎么能用接口创建对象呢,拜托给说说。
五:还请各位高手给说说还应该注意什么问题。 --------------------编程问答-------------------- http://www.asp.net/learn/dataaccess/tutorial01cs.aspx?tabid=63 DAL
http://www.asp.net/learn/dataaccess/tutorial02cs.aspx?tabid=63 BLL
--------------------编程问答-------------------- @_@ --------------------编程问答-------------------- 偶觉得初学还没必要过于考究架构的细节,了解理论,慢慢体会~
SQLHelper相当于一把瑞士军刀,提供的只是便利而以,跟三层结构没有太大关系~ --------------------编程问答-------------------- 一:我这算算三层结构?
========
算,类 Petshop .net 和 Java POJO 型
二:各个层的引用对吗?有没有多余或缺少的?
========
对
相对三层来说,没有,
然而,通常需要一个系统框架层或者一个实用通用层,它跨所有的层,提供各个层需要系统的公共服务,例如你可能常见的以 SystemFramework 或者 Common 命名的项目
三:我看网上很多都用SQLHelper这个名字,我也不知道SQLHelper这里面的内用是不是和我写的这个差不多?
==========
不是,你见到的应该是经典意义的 SqlHelper, 其实它是封装 ADO.NET 基本操作的一个实用类,它为整个 DAL 服务,而你这个 SqlHelper 只为 User 服务,也许你会说,我可以往其中加入其他 Entity 的 CRUD 操作,那么也不是,
比较经典的,应该是酱紫
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using Model;
using DBUtility; // -> SqlHelper
namespace DAL
{
public class SQLHelper
{
public DataSet GetAllUserInfo()
{
string strSQL = "Select * From UserInfo";
//SqlConnection con = new SqlConnection("Data Source = (local);Integrated Security = //SSPI;Initial Catalog = DBFile;");
//SqlDataAdapter da = new SqlDataAdapter(strSQL, con);
//DataSet ds = new DataSet();
//da.Fill(ds, "UserInfo");
string strSQL = "Select * From UserInfo";
SqlConnection con = SqlHelper.CreateConnection();
DataSet ds = SqlHelper.ExecuteDataSet(con, strSql);
return ds;
}
public bool Insert(UserEntity userEntity)
{
string UserName = userEntity.UserName;
string Sex = userEntity.Sex;
string Email = userEntity.Email;
string Phone = userEntity.Phone;
string Address = userEntity.Address;
string strSQL = "Insert Into UserInfo Values('" + UserName + "','" + Sex + "','" + Email + "','" + Phone + "','" + Address + "')";
SqlConnection conn = SqlHelper.CreateConnection();
//SqlConnection con = new SqlConnection("Data Source = (local);Integrated Security = //SSPI;Initial Catalog = DBFile;");
//SqlCommand com = new SqlCommand(strSQL, con);
try
{
//con.Open();
//com.ExecuteNonQuery();
int affectedRecords = SqlHelper.ExecuteNonQuery(strSQL);
// 根据实际需要,是否检查返回的实际操作影响的行数
// return (affectedRecords > 0)
return true;
}
catch
{
// 应该丢出异常,由高层捕获处理
throw;
//return false;
}
finally
{
//con.Close();
}
}
}
return false;
}
--------------------编程问答-------------------- 我觉得这已经很不错了。 --------------------编程问答-------------------- 你可以详细到 SqlHelper 应该是个怎么样的,
其实它还是一个纯 ADO.NET ,不与具体的系统发生耦合的,
你可以去下载,随便 baidu 一个就出来了
当然,最新的应该是 Enterprise Library, 但是毕竟复杂了
四:听人说用接口创建对象,我不明白,接口是个契约,里面不都是定义的函数吗,怎么能用接口创建对象呢,拜托给说说。
===============
也许你听到的,应该是,面向接口编程,
比如,按你这里的设计,考虑到以后数据库移植或者数据持久化策略的变动
会在 DAL 和 BLL 中设计一个 IDAL,DAL 实现 IDAL 中定义的接口,
那么,也许你最初客户要求数据库选择的是MS SQL Server,可以实现一个 SQLServerDAL,
后来,某种商业或业务需求的原因,客户觉得 Oracle 比较合适,这时候,你只要实现一个 OracleDAL,取代原来的 SQLServerDal,
或者,你的系统目标就是多套数据库支持,那么一般这样设计的,
而上层 BLL UI 都不需要做变化,或者变化是很小的(通过配置)
我不举例了,你下个 Petshop 3 (最新的是 4.0, 但是建议你从 3.0 开始,4.0 搞得态复杂了),下来看看就知道了
五:还请各位高手给说说还应该注意什么问题。
==========
实在太多了,不是纸上谈兵可以说清楚的,
主要是由于,没有实践,你不会有感触,
从实践中去慢慢深刻体会吧,
Good Luck!
--------------------编程问答-------------------- 关注,帮顶 --------------------编程问答-------------------- Jinglecat(晓风残月 >> 问题需简洁,错误要详细)
非常感谢
还有一个问题请教一下:
我在表现层,都是直接用txtUserName.Text....等等的值直接传到BLL层来做检测的,请问我能否在表现层把这个txtUserName等等,赋予给一个UserEntity对象,然后在BLL写一个函数,参数是UserEntity对象,然后在表现层直接将UserEntity对象转递给BLL去验证,可以吗?? --------------------编程问答-------------------- Mark --------------------编程问答-------------------- UP
--------------------编程问答-------------------- 验证的东西不一定要全放到业务层的,具体看项目而定.权衡使用
初学,已经很不错了 --------------------编程问答-------------------- mark --------------------编程问答-------------------- 都是直接用txtUserName.Text....等等的值直接传到BLL层来做检测的,请问我能否在表现层把这个txtUserName等等,赋予给一个UserEntity对象,然后在BLL写一个函数,参数是UserEntity对象
========
对了,这一点忘了,给你我的建议了
你的想法是合理的,
事实上,我是第一次看到你的 BLL 中 CheckXxx 这样的代码,感觉有点“怪”
其实,C# 的属性 set 访问器是一个最佳执行业务逻辑判断的地方,你没有必要在 BLL 中用 ChechXXX, 按你的设计是一个 BLL 实例只能对应一个 Entity 实例,
通常,我是这样设计的
// Model
public class UserEntity
{
// ...
public string UserName
{
get { return _UserName; }
set {
// 执行业务逻辑检查
if (value.Length > 20 || String.IsNullOrEmpty(value))
{
throw new Exception("用户名不合法。");
}
_UserName = value;
}
// ...
}
// BLL
namespace BLL
{
public class UserInfo
// ...
public bool Insert(UserEntity user) // 传递 UserEntity
{
return new UserDb.Insert(user);
}
// ...
}
也就是Entity/Model(实体对象,域模型) 作为数据实体在层雨层之间传递
Hope helpful! --------------------编程问答-------------------- 1. 不要用字符串拼接语句..用参数
2.
try
{
con.Open();
com.ExecuteNonQuery();
return true;
}
catch
{
return false;
}
finally
{
con.Close();
}
你这一return ,连接是否能关就是未知之数了 --------------------编程问答-------------------- finally是不管如何都会关的,不用担心
用参数的SQL语句或存储过程,这个倒是搂主应该要注意的问题 --------------------编程问答-------------------- 算三层,跟petshop结构差不多,只是在petshop4里引用的数据工厂 --------------------编程问答-------------------- 上的 --------------------编程问答-------------------- 也在研究学习三层,根据PetShop4.0写了简单的三层....
可以交流互相探讨啊....
msn: liangyi_neil@hotmail.com --------------------编程问答-------------------- 学了,顶上。
我也初学3层。 --------------------编程问答-------------------- 学习
楼主不错~! --------------------编程问答-------------------- ding --------------------编程问答-------------------- UP --------------------编程问答-------------------- 还不算三层 --------------------编程问答-------------------- 请问代码怎么使用的?我的330605650 加我QQ告诉我啊 谢谢了 --------------------编程问答-------------------- 四:听人说用接口创建对象,我不明白,接口是个契约,里面不都是定义的函数吗,怎么能用接口创建对象呢,拜托给说说
---------------------------
你听说的通过接口创建对象,应该是利用“工厂模式+反射”动态创建对象,这一技术很常使用用,楼主应该掌握 --------------------编程问答-------------------- “工厂模式+反射”动态创建对象并不提昌多用~ --------------------编程问答-------------------- 学无止境啊…… --------------------编程问答-------------------- 嗯,学习了,看来只能在实际的项目中去体会了 --------------------编程问答-------------------- jinglecat老兄真是个热心人啊 --------------------编程问答-------------------- 呵呵,先操作数据,再考虑业务逻辑,后嘛,表示出来,OK。我是这样理解三层的。 --------------------编程问答-------------------- 学习了,谢谢 --------------------编程问答-------------------- 学习哈
顶 --------------------编程问答--------------------
finally是肯定会执行的吧!!! --------------------编程问答-------------------- 感觉还是不错的 有了工厂模式的雏形
加油吧 --------------------编程问答-------------------- web层一般不调用dal层。 --------------------编程问答-------------------- web层一般不调用dal层。 --------------------编程问答-------------------- 学习 --------------------编程问答-------------------- 学习了 --------------------编程问答-------------------- SqlHelper理解有点问题,Helper顾名思义,就是帮助DAL来执行数据库操作的,所以一般都是对ado.net方法的封装,供DAL层调用,在DAL就应该看不到sqlconnection,sqlcommand...一类的对象。sqlhelper内的方法一般都是静态方法,可供dal方便调用。如:
/// <summary>
/// 执行单条增删改操作
/// </summary>
/// <param name="strSQL">增删改语句</param>
/// <returns></returns>
public bool ExecuteSQL(string connString, string strSQL)
{
bool ReturnResult = false;
SqlConnection Conn = new SqlConnection(connString);
Conn.Open();
try
{
SqlCommand MyCommand = new SqlCommand();
MyCommand.Connection = Conn;
MyCommand.CommandText = strSQL;
MyCommand.ExecuteNonQuery();
ReturnResult = true;
}
catch (Exception Ex)
{
ReturnResult = false;
throw Ex;
}
finally
{
Conn.Close();
}
return ReturnResult;
}
补充:.NET技术 , ASP.NET