兵马未动,粮草先行,开始项目的时候我习惯为项目起一个漂亮的名字,好的开始是成功的一半嘛,一个帅的名字能让我做的更有激情。
呵呵,废话少说,我给项目起的名字是:ElegantSharp,Elegant:优雅的,Sharp:尖锐、锋利。
好的架构注定是优雅的,漂亮的;而且必定是尖锐锋利的。
一、技术选型
我们要实现的架构是RichClient(富客户端)+Restful(SOA)+JPA(持久化机制),本架构也是目前系统架构的主流趋势。
1、首先分析富客户端技术,UI作为直接接触用户的层面,交互性、稳定性、速度、美观、便捷、友好是主要的研究方向,目前市面上比较流行的RichCilent技术主要有:JQuery,Ext.Net(Extjs),Dojo。
JQuery:轻量、开源、资源繁多、也是最受欢迎的富客户端技术,但相对来说控件库不足,仍需要用户自己扩展实现。
Ext.net:不支持MVC3.0的Razor模式,直接放弃,另一个基于Ext.net的框架以前已经实现过,并且做了很多的企业应用系统,总体来说Ext.net能大大提高开发效率,而且有丰富的控件库,但ADSL外网网络基本上会卡死,另外如果页面控件多了,浏览器占用内存相当严重,比较适合做企业内部不太复杂的应用(想学习的朋友可以看:http://www.cnblogs.com/qidian10/archive/2011/01/24/1943489.html)。
Extjs:收费,学习代价相对较高,暂不考虑
Dojo:学习成本较高,而且以前从未搞过
那么我们初步选型采用JQuery UI来实现UI层。
2、Restful(服务层)
据我所知,在C#里面实现Restful,貌似WCF Rest提供一套机制,看过一套源码。另外据说MVC也支持Restful,但目前还没发现应该怎么用,这一块的技术先暂时放一下,还需要慢慢研究下,如果有熟悉的朋友,请您留言,学习一下。
3、JPA(JAVA里的概念),持久化机制,目前比较火的主要有DBUtility,NHibernate,EF4.x(EF5.x)。
以前的开发一直用的是自己封装好的一套ORM,问题虽然没发现,但总感觉不靠谱,这次既然要做一套比较主流的架构,那么也应该配用潮流的东西。Nhibernate以前一用过,但总感觉要配置太多的东西,尤其是引入Spring.Net,只是配置文件就要好多。理所当然我选择了EF4.x配合Linq确实挺爽的,而且EF5马上要到来,据说性能大大的提高了。
4、Of Course 整体UI架构风格采用非常爽的MVC3.0 Razor模式。
二、搭建ElegantDAL层(数据访问层)
要实现的工作:
1、查询所有(FindALL)、分页查询(FindByPage)、获取行数(GetTotalCount)、根据条件获取记录(FindByConditions)、获取单个实体(FindById)、Insert、Update、Delete
2、采用泛型,将这些方法应用到所有的Model
3、配置EF
(1)首先创建数据表:
CREATE TABLE [dbo].[WMS_USERFUN](
[funid] [int] primary key,
[funno] [varchar](200) NOT NULL,
[funname] [varchar](100) NOT NULL,
[fatherid] [int] NULL
)
CREATE TABLE [dbo].[WMS_ROLEFUN](
[pid] [int] IDENTITY(1,1) primary key,
[roleid] [int] NOT NULL,
[funid] [int] NOT NULL
)
(2)新建MVC3.0网站,同时创建三个个类库,一个是ElegantModel,一个是ElegantDAL,一个是ElegantBLL
(3) 创建两个表的Model
Model接口文件IEntity
namespace ElegantModel
{
public interface IEntity
{
int Id { get; }
}
}
using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
/**
* 作者:陈杰
* QQ : 710782046
* Email:[email protected]
* Web :http://www.ChinaCloudTech.com
*/
namespace ElegantModel
{
public class WMS_USERFUN : IEntity
{
public WMS_USERFUN() { }
#region 属性
/// <summary>
/// 节点ID
/// </summary>
/// //指定该为主键
[Key,Column("funid")]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
/// <summary>
/// 功能链接
/// </summary>
public string funno { get; set; }
/// <summary>
/// 功能名称
/// </summary>
public string funname { get; set; }
/// <summary>
/// 父节点
/// </summary>
public int fatherid { get; set; }
#endregion
}
}
using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
/**
* 作者:陈杰
* QQ : 710782046
* Email:[email protected]
* Web :http://www.chinacloudtech.com
*/
namespace ElegantModel
{
public class WMS_ROLEFUN:IEntity
{
#region 构造函数
public WMS_ROLEFUN()
{ }
#endregion
#region 属性
[Key,Column("pid")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id
{
get;
set;
}
public int roleid
{
get;
set;
}
public int funid
{
get;
set;
}
#endregion
}
}
(3)在ElegantDAL层中,通过NuGet获取最新的EF包,然后创建一个基类:RepositoryBase.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity;
using ElegantModel;
namespace ElegantDAL
{
public class DB : DbContext
{
//配置连接串
public DB() : base("DBConStr") { }
public DbSet<WMS_USERFUN> WMS_USERFUN { get; set; }
public DbSet<WMS_ROLEFUN> WMS_ROLEFUN { get; set; }
}
public abstract class RepositoryBase
{
#region 单件模式创建一个类对象
private static DB dbContext = null;
protected static DB CreateInstance()
{
if (dbContext == null)
dbContext = new DB();
return dbContext;
}
#endregion
public DB _db = CreateInstance();
}
}
因为基类里面配置了连接串,所以请在Web.config中加入相应的配置。
<configuration>
<connectionStrings>
<add name="DBConStr"
connectionString="Data Source=localhost;User ID=sa;Password=ovenjackchain;DataBase=WebMisSharp;"
providerName="System.Data.SqlClient" />
</connectionStrings>
.....
创建上述方法的接口和实现类,这里用到了泛型和Linq的知识,不懂的可以留言询问。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace ElegantDAL
{
public interface IEFRepository<T> where T:class
{
List<T> FindAll();
List<T> FindByConditions(Func<IQueryable<T>, IOrderedQueryable<T>> order, params Expression<Func<T, bool>>[] filters);
List<T> FindByPage(int startIndex, int pageSize, Func<IQueryable<T>, IOrderedQueryable<T>> order, Expression<Func<T, bool>> filters);
int GetCount(Expression<Func<T, bool>> filters);
T FindById(int Id);
bool Insert(T _t);
bool Update(T _t);
bool Delete(T _t);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity;
using ElegantModel;
using System.Data;
using System.Linq.Expressions;
namespace ElegantDAL
{
public class EFRepository<T> : RepositoryBase, IEFRepository<T> where T : class,IEntity
{
/// <summary>
/// 获取所有的数据
/// </summary>
/// <returns></returns>
public List<T> FindAll()
{
return DBSET.ToList();
}
/// <summary>
/// 根据查询条件和排序方法返回结果集
/// </summary>
/// <param name="order">排序方法的委托</param>
/// <param name="filters">查询条件</param>
public List<T> FindByConditions(Func<IQueryable<T>, IOrderedQueryable<T>> order, params Expression<Func<T, bool>>[] filters)
{
try
{
IQueryable<T> rs = DBSET.AsQueryable();
if (filters != null)
{
foreach (var filter in filters)
{
if (filter != null)
{
rs = rs.Where(filter);
}
}
}
if (order != null)
{
rs = order(rs);
}
return rs.ToList();
}
catch
{
throw;
}
}
/// <summary>
/// 根据开始索引、每页大小查询条件和排序方法返回分页结果集,适用于前台分页件
/// </summary>
/// <param name="startIndex">开始索引</param>
/// <param name="pageSize">页面大小</param>
/// <param name="totalCount">数据总数</param>
/// <param name="order">排序方法的委托</param>
/// <param name="filters">查询条件</param>
public List<T> FindByPage(int startIndex, int pageSize,Func<IQueryable<T>, IOrderedQueryable<T>> order, Expression<Func<T, bool>> filters)
{
try
{
IQueryable<T> rs = order(DBSET.Where(filters));
if (startIndex < 0 || pageSize < 1)
{
return rs.ToList();
}
else
{
return rs.Skip(startIndex * pageSize).Take(pageSize).ToList();
}
}
catch
{
throw;
}
}
/// <summary>
/// 根据条件获取总数据行数
/// </summary>
/// <param name="conditions"></param>
/// <returns></returns>
public int GetCount(Expression<Func<T, bool>> filters)
{
return DBSET.Count(filters);
}
/// <summary>
/// 根据ID获取实体
/// </summary>
/// <param name="Id">实体主键ID</param>
/// <returns>返回实体</returns>
public T FindById(int Id)
{
return DBSET.Single(t => t.Id == Id);
}
/// <summary>
/// 插入
/// </summary>
/// <param name="_t">实体</param>
/// <returns>是否成功</returns>
public bool Insert(T _t)
{
try
{
DBSET.Add(_t);
_db.SaveChanges();
return true;
}
catch
{
return false;
}
}
/// <summary>
/// 更新
/// </summary>
/// <param name="_t">实体</param>
/// <returns>是否成功</returns>
public bool Update(T _t)
{
try
{
var entry = _db.Entry(_t);
if (entry.State == EntityState.Detached)
{
entry.State = EntityState.Modified;
}
_db.SaveChanges();
return true;
}
catch
{
return false;
}
}
/// <summary>
/// 删除
/// </summary>
/// <param name="_t">实体</param>
/// <returns>是否成功</returns>
public bool Delete(T _t)
{
try
{
DBSET.Remove(_t);
_db.SaveChanges();
return true;
}
catch
{
return false;
}
}
/// <summary>
/// 泛型数据表属性
/// </summary>
protected DbSet<T> DBSET
{
get
{
return _db.Set<T>();
}
}
/// <summary>
/// 操作提交
/// </summary>
//public override void SaveChanges()
//{
// base.SaveChanges();
//}
}
}
三、数据访问层大功告成了,接下来实现BLL层,BLL就相对简单了,主要用到一个工厂模式。
BLL我就暂时不写接口了
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ElegantDAL;
using ElegantModel;
using System.Linq.Expressions;
namespace ElegantBLL
{
public class WMS_Core<T> where T : class,IEntity
{
IEFRepository<T> IEF = new EFRepository<T>();
public List<T> FindAll()
{
return IEF.FindAll();
}
public List<T> FindByConditions(Func<IQueryable<T>, IOrderedQueryable<T>> order, params Expression<Func<T, bool>>[] filters)
{
return IEF.FindByConditions(order, filters);
}
public List<T> FindByPage(int startIndex, int pageSize, Func<IQueryable<T>, IOrderedQueryable<T>> order, Expression<Func<T, bool>> filters)
{
return IEF.FindByPage(startIndex, pageSize, order, filters);
}
public int GetCount(Expression<Func<T, bool>> filters)
{
return IEF.GetCount(filters);
}
public T FindById(int Id)
{
return IEF.FindById(Id);
}
public bool Insert(T _t)
{
return IEF.Insert(_t);
}
public bool Update(T _t)
{
return IEF.Update(_t);
}
public bool Delete(T _t)
{
return IEF.Delete(_t);
}
}
}
工厂
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ElegantModel;
namespace ElegantBLL
{
public class WMS_Factory
{
public static WMS_Core<WMS_USERFUN> WMS_USERFUN { get { return new WMS_Core<WMS_USERFUN>(); } }
public static WMS_Core<WMS_ROLEFUN> WMS_ROLEFUN { get { return new WMS_Core<WMS_ROLEFUN>(); } }
}
}
四、在UI层里面实现测试,这里只做测试,具体JQuery怎么交互,后面的文章介绍。
我们在HomeController里面写入如下代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ElegantBLL;
using ElegantModel;
namespace ElegantSharp.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "欢迎使用 ASP.NET MVC!";
ViewBag.Count = WMS_Factory.WMS_USERFUN.GetCount(c => true);
ViewBag.SingleEntity = WMS_Factory.WMS_USERFUN.FindById(1230);
ViewBag.FirstPage = WMS_Factory.WMS_USERFUN.FindByPage(1, 3, rs => rs.OrderByDescending(c => c.Id), c => true);
ViewBag.FirstPageCon = WMS_Factory.WMS_USERFUN.FindByPage(0, 3, rs => rs.OrderByDescending(c => c.Id), c => c.fatherid != 0 && c.fatherid != 2000);
/*
WMS_USERFUN w = new WMS_USERFUN();
w.fatherid = 0;
w.funname = "测试xxxx";
w.funno = "abc";
w.Id = 3000;
//测试插入
WMS_Factory.WMS_USERFUN.Insert(w);
//测试更新
WMS_Factory.WMS_USERFUN.Update(w);
WMS_ROLEFUN rolefun = WMS_Factory.WMS_ROLEFUN.FindById(25);
//测试删除
if (rolefun != null)
WMS_Factory.WMS_ROLEFUN.Delete(rolefun);
*/
return View(WMS_Factory.WMS_USERFUN.FindAll());
}
public ActionResult About()
{
return View();
}
}
}
运行结果如下:
好了,到这里,可以说我们架构搭建只完成了30%,为什么这么说,因为聪明的你会发觉,通篇其实只是做了EF的配置和泛化方法,那么在后面的文章中将会继续探索UI层的JQuery框架实现和Restful的实现,同时希望大牛们能够提供技术支持,技术思路。欢迎留言评论。