上一篇博客中《两天完成一个小型工程报价系统》,许多朋友向我讨源码。其实我之后没发了,确实那种三层架构没什么意思,只是我个人的孤芳自赏,很多的处理都不是很成熟。所以我重新架构了一番,以一个小例子来阐述我的架构模式,当然,这和企业级的架构还是差距很大,不过,还是值得一读。不积硅步,无以至江海,只有从小细节慢慢领悟,步步为营,才能设计出优秀的企业级架构。
这儿使用了Repository模式,抽象出一个公共的接口IBaseDao,IBaseDao接口中定义了一系列契约(CRUD ),不管我的我数据访问用了那种技术,只要我实现了IBaseDao接口,则必须要实现接口定义的契约,所以接口的稳定至关重要,当然这样做的好处是显而易见的,减少了冗余代码。
public interface IBaseDao<T> where T:class
{
IList<T> GetAllEntities();
bool SaveEntity(T entity);
bool UpdateEntity(T entity);
bool DeleteEntity(T entity);
bool DeleteEntityByID(object id);
T GetEntityByID(object id);
IList<T> GetPageEntities(int pageIndex, int PageSize);
}
public interface ICustomerDao<Customer>:IBaseDaopublic interface ICustomerDao:IBaseDao<Customer>
public interface ICustomerDao:IBaseDao<Customer>
{
}
public class CustomerOracleDao:IDao.ICustomerDao
{
public IList<Model.Customer> GetAllEntities()
{
return GetAllEntitiesBySqlWhere("");
}
public IList<Model.Customer> GetAllEntitiesBySqlWhere(string sqlWhere)
{
string sql = string.Format("select * from Customer Where 1=1 {0}",sqlWhere);
List<Customer> listCustomers = new List<Customer>();
using (OracleDataReader odr = OracleHelper.ExecuteReader(OracleHelper.ConnectionString, System.Data.CommandType.Text, sql, null))
{
while (odr.Read())
{
Model.Customer customer = new Customer();
customer.ID = odr.GetInt32(0);
customer.Name = odr.IsDBNull(1) ? "" : odr.GetString(1);
customer.Phone = odr.IsDBNull(2) ? "" : odr.GetString(2);
customer.Remark = odr.IsDBNull(3) ? "" : odr.GetString(3);
listCustomers.Add(customer);
}
}
return listCustomers;
}
private int GetNewID()
{
string sql = "select s_customer.nextval from dual";
return int.Parse(OracleHelper.ExecuteScalar(OracleHelper.ConnectionString, CommandType.Text, sql, null).ToString());
}
public bool SaveEntity(Model.Customer entity)
{
entity.ID = GetNewID();
bool resultValue = false;
string sql = string.Format(@"insert into Customer(ID,Name,Phone,Remark) values({0},'{1}','{2}','{3}')",entity.ID,entity.Name,entity.Phone,entity.Remark );
if (OracleHelper.ExecuteNonQuery(OracleHelper.ConnectionString, CommandType.Text, sql, null) > 0)
{
resultValue = true;
}
return resultValue;
}
public bool UpdateEntity(Model.Customer entity)
{
string sql = string.Format("update Customer set Name='{0}',Phone='{1}',Remark='{2}' where ID={3}",entity.Name,entity.Phone,entity.Remark,entity.ID);
return OracleHelper.ExecuteNonQuery(OracleHelper.ConnectionString, CommandType.Text, sql, null) > 0;
}
public bool DeleteEntity(Model.Customer entity)
{
return DeleteEntityByID(entity.ID);
}
public bool DeleteEntityByID(object id)
{
string sql = string.Format("delete from Customer where ID={0} ",id);
return OracleHelper.ExecuteNonQuery(OracleHelper.ConnectionString, CommandType.Text, sql, null) > 0;
}
public Model.Customer GetEntityByID(object id)
{
string sqlWhere = string.Format(" and id={0}", id);
int CID = (int)id;
List<Model.Customer> list = GetAllEntitiesBySqlWhere(sqlWhere) as List<Customer>;
return list.SingleOrDefault(c => c.ID == CID);
}
public IList<Model.Customer> GetPageEntities(int pageIndex, int PageSize)
{
throw new NotImplementedException();
}
}
//用EF来实现数据访问层接口
public class CustomerEFDao:ICustomerDao
{
//上下文网关
private Hotel.Model.HotelContainer hotelDB = new Model.HotelContainer();
/// <summary>
/// 获取全部用户信息
/// </summary>
/// <returns></returns>
public IList<Insigma.Hotel.Model.Customer> GetAllEntities()
{
return hotelDB.Customer.ToList<Customer>();
}
public bool SaveEntity(Insigma.Hotel.Model.Customer entity)
{
hotelDB.Customer.AddObject(entity);
bool returnValue = false;
//返回受影响的行数
if (hotelDB.SaveChanges()>0)
{
returnValue = true;
}
return returnValue;
}
/// <summary>
/// 更新客户信息
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public bool UpdateEntity(Insigma.Hotel.Model.Customer entity)
{
//新的方法来保存
//hotelDB.Customer.Attach(entity);//附加到表对应集合缓冲中
//hotelDB.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Modified);
bool resultValue = false;
//if (hotelDB.SaveChanges()>0)
//{
// resultValue = true;
//}
//return resultValue;
HotelContainer hoteEntities = new HotelContainer();
var oldCustomer = (from c in hoteEntities.Customer
where c.ID == entity.ID
select c).SingleOrDefault<Customer>();
oldCustomer.Name = entity.Name;
oldCustomer.Phone = entity.Phone;
oldCustomer.Remark = entity.Remark;
if (hoteEntities.SaveChanges()>0)
{
resultValue = true;
}
return resultValue;
}
/// <summary>
/// 删除客户信息(一般是软删除)
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public bool DeleteEntity(Insigma.Hotel.Model.Customer entity)
{
return DeleteEntityByID(entity.ID);
}
/// <summary>
/// 根据ID删除数据
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public bool DeleteEntityByID(object id)
{
int Id = (int)id;
bool resultValue = false;
var deleteCustomer = hotelDB.Customer.Where<Customer>(c => c.ID == Id).SingleOrDefault<Customer>();
if (deleteCustomer != null)
{
hotelDB.Customer.DeleteObject(deleteCustomer);
if (hotelDB.SaveChanges() > 0)
{
resultValue = true;
}
}
return resultValue;
}
/// <summary>
////// </summary>
/// <param name="id"></param>
/// <returns></returns>
public Insigma.Hotel.Model.Customer GetEntityByID(object id)
{
int Id = (int)id;
return hotelDB.Customer.Where<Customer>(c => c.ID == Id).SingleOrDefault<Customer>();
}
public IList<Insigma.Hotel.Model.Customer> GetPageEntities(int pageIndex, int PageSize)
{
var result = hotelDB.Customer.OrderBy(c =>c.ID).Skip<Customer>((pageIndex - 1) * PageSize).Take<Customer>(PageSize).ToList();
return result;
}
}
public class CustomerSQLDao:ICustomerDao
{
public IList<Insigma.Hotel.Model.Customer> GetAllEntities()
{
using (CustomerTableAdapter adapter=new CustomerTableAdapter ())
{
var result = (from c in adapter.GetData()
select new Customer { ID=c.ID,Name=c.Name,Phone=c.Phone}).ToList<Customer>();
return result;
}
}
public bool SaveEntity(Insigma.Hotel.Model.Customer entity)
{
bool resultValue=false;
using (CustomerTableAdapter adapter=new CustomerTableAdapter ())
{
if (adapter.Insert(entity.Name, entity.Phone, entity.Remark) > 0)
{
resultValue = true;
}
return resultValue;
}
}
public bool UpdateEntity(Insigma.Hotel.Model.Customer entity)
{
bool resultValue = false;
using (CustomerTableAdapter adapter=new CustomerTableAdapter ())
{
if (adapter.UpdateCustomer(entity.Name,entity.Phone,entity.Remark,entity.ID)>0)
{
resultValue = true;
}
return resultValue;
}
}
public bool DeleteEntity(Insigma.Hotel.Model.Customer entity)
{
return DeleteEntityByID(entity.ID);
}
public bool DeleteEntityByID(object id)
{
bool resultValue = false;
int CID=(int)id;
using (CustomerTableAdapter adapter=new CustomerTableAdapter ())
{
//若取名Delete会变成Delete1
if (adapter.DeleteCustomerByID(CID)>0)
{
resultValue = true;
}
return resultValue;
}
}
public Insigma.Hotel.Model.Customer GetEntityByID(object id)
{
using (CustomerTableAdapter adapter=new CustomerTableAdapter ())
{
var table=adapter.GetCustomerByID(Convert.ToInt32(id));
Customer customer = new Customer();
customer.ID = table[0].ID;
customer.Name = table[0].Name;
customer.Phone = table[0].Phone;
return customer;
}
}
public IList<Insigma.Hotel.Model.Customer> GetPageEntities(int pageIndex, int PageSize)
{
using (CustomerTableAdapter adapter=new CustomerTableAdapter ())
{
var result = (from c in adapter.GetData()
select new Customer { ID = c.ID, Name = c.Name, Phone = c.Phone }).OrderBy(c => c.ID).Skip<Customer>((pageIndex - 1) * PageSize).Take<Customer>(PageSize).ToList<Customer>();
return result;
}
}
}
这样我们就设计好了数据访问层实现方式,一共有三层方法来实现对数据库的访问,但是不管是OracleDao,还是EFDao,SQLDao实现了IBaseDao接口。这就是Repository模式。
public interface ICustomerService
{
//Controller来调用业务逻辑
IList<Customer> GetAllCustomers();
bool SaveCustomer(Customer customer);
bool UpdateCustomer(Customer customer);
bool DeleteCustomer(int id);
IList<Customer> GetPageCustomers(int pageIndex, int pageSize);
Customer GetCustomerByID(int id);
}
public class CustomerService:ICustomerService
{
public CustomerService()
{
//最好通过抽象工厂和反射 IOC依赖注入
//this.customerDao = new EFDao.CustomerEFDao();
this.customerDao = DaoFactory.GetCustomerDao();
}
/// <summary>
/// 数据表数据访问层接口(好处:接口是稳定)
/// </summary>
private ICustomerDao customerDao;
public ICustomerDao CustomerDao
{
get { return customerDao; }
set { customerDao = value; }
}
public IList<Model.Customer> GetAllCustomers()
{
return CustomerDao.GetAllEntities();
}
public bool SaveCustomer(Model.Customer customer)
{
return CustomerDao.SaveEntity(customer);
}
public bool UpdateCustomer(Model.Customer customer)
{
return CustomerDao.UpdateEntity(customer);
}
public bool DeleteCustomer(int id)
{
return CustomerDao.DeleteEntityByID(id);
}
public IList<Model.Customer> GetPageCustomers(int pageIndex, int pageSize)
{
return CustomerDao.GetPageEntities(pageIndex, pageSize);
}
public Model.Customer GetCustomerByID(int id)
{
return CustomerDao.GetEntityByID(id);
}
}
public class DaoCache
{
public DaoCache()
{
}
public static object GetDao(string key)
{
System.Web.Caching.Cache daoCache = HttpRuntime.Cache;
return daoCache.Get(key);
}
public static void InsertDaoCache(string key, object value)
{
if (GetDao(key) == null)
{
System.Web.Caching.Cache daoCache = HttpRuntime.Cache;
daoCache.Insert(key, value);
}
}
}
public class DaoFactory
{
public static readonly string DaoPath=System.Configuration.ConfigurationManager.AppSettings["DaoPath"];
public static readonly string DaoHZ=System.Configuration.ConfigurationManager.AppSettings["HZ"];
public static object CreateDao(string assemblyPath, string objType)
{
var cacheDao = DaoCache.GetDao(objType);
if (cacheDao==null)
{
cacheDao = Assembly.Load(assemblyPath).CreateInstance(objType);
DaoCache.InsertDaoCache(objType, cacheDao);
}
return cacheDao;
}
public static ICustomerDao GetCustomerDao()
{
return CreateDao(DaoPath, string.Format("{0}.Customer{1}", DaoPath, DaoHZ)) as ICustomerDao;
}
}
这样,最简单的业务逻辑层完成了,当然这儿很复杂,还需要用到Facade模式。
public class CustomerController : Controller
{
// private HotelContainer db = new HotelContainer();
private Insigma.Hotel.IBLL.ICustomerService customerService =new BLL.CustomerService();
//
// GET: /Customer/
public ViewResult Index()
{
return View(customerService.GetAllCustomers());
}
//
// GET: /Customer/Details/5
public ViewResult Details(int id)
{
Customer customer = customerService.GetCustomerByID(id);
return View(customer);
}
//
// GET: /Customer/Create
public ActionResult Create()
{
return View();
}
//
// POST: /Customer/Create
[HttpPost]
public ActionResult Create(Customer customer)
{
if (ModelState.IsValid)
{
customerService.SaveCustomer(customer);
return RedirectToAction("Index");
}
return View(customer);
}
//
// GET: /Customer/Edit/5
public ActionResult Edit(int id)
{
Customer customer = customerService.GetCustomerByID(id);
return View(customer);
}
//
// POST: /Customer/Edit/5
[HttpPost]
public ActionResult Edit(Customer customer)
{
if (ModelState.IsValid)
{
customerService.UpdateCustomer(customer);
return RedirectToAction("Index");
}
return View(customer);
}
//
// GET: /Customer/Delete/5
public ActionResult Delete(int id)
{
Customer customer = customerService.GetCustomerByID(id);
return View(customer);
}
//
// POST: /Customer/Delete/5
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
customerService.DeleteCustomer(id);
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
}
}
<add key="DaoPath" value="Insigma.Hotel.EFDao" /> <add key="HZ" value="EFDao" />
这是对稍早那篇文章的总结,接口引入稳定了开发。反射的引用让程序员更加关注业务层,提高了开发效率。
牛人的架构设计图:来自刘冬.NET