1.建立数据库OA,表UserInfo
2.创建类库项目以及mvc4 web项目
1)OA.Model 层:模型
2)OA.IDal 层 :数据接口
3)OA.Dal层 :数据实现
4)OA.IDBSession层 :会话接口
5)OA.DBSession 层 :会话层
6)OA.IBLL 层 :业务员接口
7)OA.BLL 层 :业务实现
8)OA.Web MVC UI层
3.编写代码
1)在model层中添加EF上下文,
2)编写数据接口层的代码:对表的操作(1增2删3改4查5分页),在分页中返回总记录数,在查询中根据用户输入的lambda表达式进行具体查询一条记录或者多条记录
//增删改查 分页 T AddEntity(T t); bool DeleteEntity(T t); bool UpdateEntity(T t); IQueryable<T> LoadEntities(Expression<Func<T,bool>> whereLambda); IQueryable<T> LoadPageEntitis<s>(int pageIndex, int pageSize, out int toalCount, Expression<Func<T, bool>> whereLambda, Expression<Func<T,s>> orderByLambda, bool IsAsc);
在分页中实现排序,并可选顺序或者逆序。LoadPageEntites<s> s代表orderByLambda值的类型,当使用id进行排序时,<s>值为int,当使用name进行排序时,<s>值为string。
因为每一张表都要实现这个接口,因此将如上“//增删改查 分页”封装成IBaseDal<T>。其他表只需要继承IBaseDal<T>,将对应的表传入T即可。
1 public interface IDeviceInfoDal : IBaseDao<SYS_DEVICE_TABLE> 2 { 3 4 }
3)编写Dal层,继承自IDal,一个表对应一个dal,例如userinfo这张表,创建UserInfoDal继承自IUserInfoDal,实现IUserInfoDal的接口,IUserInfoDal继承自IBaseDal,每一张表都需要实现这些接口((1增2删3改4查5分页)),因此,需要继续封装这些接口的实现,封装成BaseDal
1 public class BaseDal<T> 2 where T:class,new() 3 { 4 MLedSystemEntities dbContext = DBContxtFactory.CreateDbContext(); 5 public T AddEntity(T t) 6 { 7 dbContext.Entry<T>(t).State = EntityState.Added; 8 //dbContext.SaveChanges(); 9 return t; 10 } 11 12 public bool DeleteEntity(T t) 13 { 14 dbContext.Entry<T>(t).State = EntityState.Deleted; 15 return true;//dbContext.SaveChanges() > 0; 16 } 17 18 public bool UpdateEntity(T t) 19 { 20 dbContext.Entry<T>(t).State = EntityState.Modified; 21 return true;//dbContext.SaveChanges() > 0; 22 } 23 24 public IQueryable<T> LoadEntities(System.Linq.Expressions.Expression<Func<T, bool>> whereLambda) 25 { 26 return dbContext.Set<T>().Where(whereLambda); 27 } 28 29 public IQueryable<T> LoadPageEntitis<s>(int pageIndex, int pageSize, out int toalCount, System.Linq.Expressions.Expression<Func<T, bool>> whereLambda, System.Linq.Expressions.Expression<Func<T,s>> orderByLambda, bool IsAsc) 30 { 31 var res = dbContext.Set<T>().Where(whereLambda); 32 toalCount = res.Count(); 33 IQueryable<T> temp; 34 if (IsAsc) 35 { 36 temp = res.OrderBy<T, s>(orderByLambda).Skip((pageIndex - 1) * pageSize).Take(pageSize); 37 } 38 else 39 { 40 temp = res.OrderByDescending<T, s>(orderByLambda).Skip((pageIndex - 1) * pageSize).Take(pageSize); 41 } 42 return temp; 43 } 44 45 }
而每一张表只需要继承自BaseDal即可,如此大大提高代码重用。先继承实现,再继承接口,
public class DeviceTypeInfoDal : BaseDal<SYS_DEVICE_TYPE_TABLE>, IDeviceTypeInfoDal { }
public class DeviceInfoDal :BaseDal<SYS_DEVICE_TABLE>, IDeviceInfoDal { }
这里需要改进的地方是:每一次操作增删查改都需要savechange()一次,每一次操作都需要连接数据库,假设用户的有一次操作是关联三张表,那么一次操作就需要三次打开数据库连接,然后又关闭数据库连接,如此,效率大大下降。解决办法:将SaveChange()提取出来,使得用户操作一次无任关联多少张表,只需要一次数据库操作即可。(由会话层来实现)
4)编写中间会话层,会话层的作用是降低业务层与数据层的耦合。
编写会话层接口和实现
会话层主要作用:是对数据实现层的管理,以及如上提到的一次性SaveChange的问题。
IDeviceInfoDal DeviceInfoDal { get; set; } IDeviceTypeInfoDal DeviceTypeInfoDal { get; set; } bool SaveChange();
1 MLedSystemEntities dbContext { 2 get { 3 return DBContxtFactory.CreateDbContext(); 4 //这里需要保证EF上下文唯一,也就是线程安全 5 } 6 } 7 public IDeviceInfoDal DeviceInfoDal 8 { 9 get 10 { 11 //return DBSessionFactory.CreateDeviceInfoDal(); 12 return AbstractFactory.CreateDeviceInfoDal(); 13 //这里使用抽象工厂创建对象实例-》目的:降低耦合度 14 } set { DeviceInfoDal = value; } } public IDeviceTypeInfoDal DeviceTypeInfoDal { 15 get { 16 //return DBSessionFactory.CreateDeviceTypeInfoDal(); 17 return AbstractFactory.CreateDeviceTypeInfoDal(); 18 //这里使用抽象工厂创建对象实例-》目的:降低耦合度 19 } set { DeviceTypeInfoDal = value; } } public bool SaveChange() { return dbContext.SaveChanges()>0; }
如何保证EF上下文线程安全呢?这里使用的是CallContext这个类进行管理。
/// <summary>
/// EF上下文,线程唯一性
/// </summary>
public static MLedSystemEntities CreateDbContext()
{
MLedSystemEntities DbContext = CallContext.GetData("dbContext") as MLedSystemEntities;
if (DbContext == null) {
DbContext = new MLedSystemEntities();
CallContext.SetData("dbContext",DbContext);
}
return DbContext;
}
//抽象工厂 使用反射的方法进行 解耦
在web.config中添加配置节点
<add key="DalAssemblyPath" value="OA.Dal"/>
<add key="NameSpace" value="OA.Dal"/>
代码如下:
private static readonly string DalAssemblyPath = ConfigurationManager.AppSettings["DalAssemblyPath"];
private static readonly string NameSpace = ConfigurationManager.AppSettings["NameSpace"];
/// <summary>
/// 创建DeviceInfo实例
/// </summary>
/// <returns></returns>
public static IDeviceInfoDal CreateDeviceInfoDal()
{
string fullClassName = NameSpace + ".DeviceInfoDal";
var assembly = Assembly.Load(NameSpace);
return assembly.CreateInstance(fullClassName) as IDeviceInfoDal;
}
5)编写业务接口层和业务实现层。在业务接口层同数据操作DAL层类似
需要注意的是:需要保证会话层线程安全,同样是使用CallContext来进行管理
public DBSession CreateDBSession(){
DBSession dbSession=CallContext.GetData("dbsession") as DBSession;
if(dbSession==null){
dbSession=new DBSession();
CallContext.SetData("dbsession",dbSession);
}
return dbSession;
}
6)MVC ui层调用业务层,业务层调用会话层,会话层调用数据层。
在UI层中,添加对应表的Controller,异步加载方式获取数据。
view中:
<table border="1 solid red" id="tab">
@Html.ActionLink("添加","Create")
<tr>
<th width="50">id</th>
<th width="50">name</th>
<th width="50">ip</th>
<th width="50">port</th>
</tr>
<tbody id="list"></tbody>
</table>
js代码:
<script type="text/javascript"> $(function () { onAsynLoad(3,5); }); function onAsynLoad(pageindex, pagesize) { $.getJSON( '@Url.Action("AsynLoad","DeviceInfo")', { pageIndex: pageindex, pageSize: pagesize },//传入参数 function (temp) {//temp为返回的结果 var list = $('#list'); list.empty(); $.each(temp.list1, function (index, item) { list.append('<tr><td>' + item.id + '</td><td>' + item.Name + '</td><td>' + item.Ip + '</td><td>' + item.Port + '<a href="@Url.Action("Delete","DeviceInfo")?id=' + item.id + '">删除</a></td></tr>') }); list.append('<tr><td colspan=4>总记录数:' + temp.tolCount + '</td></tr>'); } ); } </script>
Controller中的异步加载代码:
1 public ActionResult AsynLoad(int pageIndex, int pageSize) 2 { 3 //int pageIndex=1; 4 //int pageSize=4; 5 int totalCount=0; 6 var result = DeviceInfoService.LoadPageEntitis<int>(pageIndex, pageSize, out totalCount, u => true, u => u.DEVID, true).ToList(); 7 List<DeviceInfoViewModel> listDeviceInfoViewModel=new List<DeviceInfoViewModel>(); 8 foreach(var res in result){ 9 DeviceInfoViewModel item=new DeviceInfoViewModel(); 10 item.id=res.DEVID; 11 item.Name=res.DEVNAME; 12 item.Ip=res.DEVIP; 13 item.Port=res.DEVPORT; 14 listDeviceInfoViewModel.Add(item); 15 } 16 var temp = new 17 { 18 list1 = listDeviceInfoViewModel, 19 tolCount = totalCount.ToString() 20 }; 21 return Json(temp,JsonRequestBehavior.AllowGet); 22 }
总结:关键知识点:1、EF线程安全、会话层线程安全。
2、抽象工厂创建实例解耦。
3、使用会话层解耦。
代码下载
http://files.cnblogs.com/files/jxsd/OA.Web.zip
http://files.cnblogs.com/files/jxsd/OA1.zip