求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
     
   
分享到
步步为营:三层架构+ASP.NET MVC 架构的快速搭建(入门篇)
 

发布于2013-3-21

 

重构后的架构图:

解决方案里项目设计:

数据库访问层接口设计:IBaseDao

  • Repository模式

这儿使用了Repository模式,抽象出一个公共的接口IBaseDao,IBaseDao接口中定义了一系列契约(CRUD ),不管我的我数据访问用了那种技术,只要我实现了IBaseDao接口,则必须要实现接口定义的契约,所以接口的稳定至关重要,当然这样做的好处是显而易见的,减少了冗余代码。

public interface IBaseDao where T:class
    {
        IList GetAllEntities();
        bool SaveEntity(T entity);
        bool UpdateEntity(T entity);
        bool DeleteEntity(T entity);
        bool DeleteEntityByID(object id);
        T GetEntityByID(object id);
        IList GetPageEntities(int pageIndex, int PageSize);
    }
  • 首先ICustomerDao继承了IBaseDao接口:
public interface ICustomerDao:IBaseDao
    {
    }
  • OracleDao实现ICustomerDao接口
public class CustomerOracleDao:IDao.ICustomerDao
    {
        public IList GetAllEntities()
        {
            return GetAllEntitiesBySqlWhere("");

        }
        public IList GetAllEntitiesBySqlWhere(string sqlWhere)
        {

            string sql = string.Format("select * from Customer Where 1=1  {0}",sqlWhere);
            List listCustomers = new List();
            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 list = GetAllEntitiesBySqlWhere(sqlWhere) as List;
            return list.SingleOrDefault(c => c.ID == CID);
        }

        public IList GetPageEntities(int pageIndex, int PageSize)
        {
            throw new NotImplementedException();
        }
    }
  • EFDao实现ICustomerDao接口
//用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;
}
}
  • SQLDao实现ICustomerDao接口
public class CustomerSQLDao:ICustomerDao
    {

        public IList 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();
                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 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((pageIndex - 1) * PageSize).Take(PageSize).ToList();
                return result;
            }
        }
    }

这样我们就设计好了数据访问层实现方式,一共有三层方法来实现对数据库的访问,但是不管是OracleDao,还是EFDao,SQLDao实现了IBaseDao接口。这就是Repository模式。

业务逻辑层接口设计:IBLL

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);
}
  • 这儿我们更希望通过配置文件的方式手动的去选择需要的数据访问层技术。所以这儿可以运用抽象工厂+反射的技术,当然还有IOC依赖注入
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模式。

表示层(MVC)

表示层当然是指挥家Controller去访问业务逻辑层,把数据装配到Model中,交给View来显示。

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)
{

}
}

现在只需要修改配置文件就可以灵活的选择OracleDao、EFDao、SQLDao,而我们的项目丝毫不会有任何改动:

<add key="DaoPath" value="Insigma.Hotel.EFDao" />
<add key="HZ" value="EFDao" />
 
分享到
 
 


专家视角看IT与架构
软件架构设计
面向服务体系架构和业务组件
人人网移动开发架构
架构腐化之谜
谈平台即服务PaaS



面向应用的架构设计实践
单元测试+重构+设计模式
软件架构师—高级实践
软件架构设计方法、案例与实践
嵌入式软件架构设计—高级实践
SOA体系结构实践



锐安科技 软件架构设计方法
成都 嵌入式软件架构设计
上海汽车 嵌入式软件架构设计
北京 软件架构设计
上海 软件架构设计案例与实践
北京 架构设计方法案例与实践
深圳 架构设计方法案例与实践
嵌入式软件架构设计—高级实践
更多...