学习asp.net 已经有近三个月的时间了,在asp.net mvc上花的时间最多,但个人真是有些菜,不得不说,asp.net mvc的水真的还是蛮深的。目前在公司实习,也见过公司几个项目的代码了。对项目的代码始终停留在一知半解的地步,能改一些简单的bug,但关于项目的来龙去脉始终云里雾里。对于asp.net mvc的架构始终看不懂。因此,照着传智博客的学习视频,学了一下简单的架构搭建。真个架构的搭建我看了将近两遍视频,才稍稍有些头绪,今天在这里记录一下,一方面加深理解,一方面如果以后忘记了,还能快速的想起来,当然如果我的这篇简陋的随笔能有幸被有需要的人看见,并对他们产生一些帮助,我心里肯定也是非常欢欣的。

  好了,闲言少叙,那我就开始写了。

  本篇博客我主要想讲如何使用 asp.net mvc + EF + spring.net 搭建一个简单的项目框架,我也并不是对前前后后所有的内容都理解,有的地方是囫囵吞枣,水平太菜,见谅。

在开始搭框架之前,先做一些准备工作:

(1)新建解决方案:

新建一个解决方案,然后在解决方案下间五个文件夹,分别为 Common、Bll、Dal、Model、UI.如下图所示:

(说明:我的项目命名为IotPf.Proj,因为之前做过一个物联网云平台的项目,这里打算用.net重做实践一下,练练手)

(2)在Model层中新建类库 Model,然后添加EF数据库实体

  添加实体的操作我就不啰嗦了,我以前的博客有讲到。结果如下:

(3)分别在Bll里新建类库 XXX.Bll 和 XXX.IBll,在Dal里新建XXX.Dal和XXX.IDal,如图所示:

(4)在UI下面新建应用程序IotPf.UI

好了,准备工作已经做好了,下面进入正题。

1.首先在IofPf.Dal中新建UsersDal.cs文件,这个里面写对于User表的增删改查等系列数据库操作。如下入图所示:

下面列出在UserDal中写的关于增删改查几个最常用操作的最基本写法,然后对其进行调用(当然只是那种最简单的调用,不涉及如和进行解耦的操作):

看代码:

  public  class UserDal
{
IotPfModel context = new IotPfModel();
//使用lambda表示式查询
public IQueryable<Users> GetUsersByLambda(Expression<Func<Users,bool>> wherelambda)
{
return context.Users.Where(wherelambda).AsQueryable(); } //分页查询
#region 增删改
public Users AddUser(Users user)
{
context.Users.Add(user);
context.SaveChanges();
return user;
} public bool DeleteUser(Users user)
{
context.Entry(user).State = System.Data.Entity.EntityState.Deleted;
return context.SaveChanges() > ;
} public bool UpdateUser(Users user)
{
context.Entry(user).State = System.Data.Entity.EntityState.Modified;
return context.SaveChanges() > ;
}
#endregion
}

UserDal

上面的代码写了增删改查四个方法,其中查询的方法是根据lambda表达式自定义查询条件。

上面的代存在一下几个方面的问题:(以很通俗化的语言描述,不写菜鸟看不懂的话)

(1)首先,UserDal中对数据库进行操作首先要做的就是实例化上下文。目前,我们使用的是单一的EF操作数据库,所以实例化的就是EF的上下文,但是,操作数据的方式不止EF这一种,如果有一天我们的项目突然要求要用NH(另一种操作数据库的方式,但我没学过)操作数据库,那么如果我们像这样写的话,麻烦就大了。我们的项目肯定不会只有一个XXXDal,有很多个的,如果上下文变了,那我们就要改好多个XXXDal里的代码,这就牵一发而动全身了,相当麻烦,这就是第一个问题。

解决方法可以把实例化上下文的操作单独的放在一个类中,在类中定义一个 GetDalContext()的方法,然后所有的XXXDal都可以调用这个方法,如果上下文变了,那么只需要改这一个文件就可以了,这就灵活一些了。

具体做法:

在IotPf.Dal中新建DbContextFactory.cs文件,然后编写代码如下:

  public  class DbContextFactory
{
public static DbContext GetCurrentDbContext()
{
return new IotPfModel();
}
}

优化后的写法如下:

  public static DbContext GetCurrentDbContext()
{
DbContext context = CallContext.GetData("DbContext") as DbContext;
if (context == null)
{
context = new IotPfModel();
CallContext.SetData("DbContext", context);
} return context;
}

(别问我为啥这么优化,尴尬的告诉你,本菜鸡不知道啊!)

(2)其次,UserDal中的这几个方法是最最常用的方法,几乎每个XXXDal中都会用到这四个方法,那我们就在每个XXXDal中都写一遍吗?这显然是不合理的,这是无用功;

解决方法:常用的公共的方法,可以封装到一个基类中,所有需要用到的类都继承这个基类就可以了;

具体做法:

在IotPf.Dal下新建一个BaseDal.cs,然后编辑代码如下:

 public  class BaseDal<T> where T : class ,new()
{
//实例化上下文
DbContext context = DbContextFactory.GetCurrentDbContext();
//使用lambda条件进行查询
public IQueryable<T> GetEntityByLambda(Expression<Func<T,bool>> wherelambda)
{
return context.Set<T>().Where(wherelambda).AsQueryable();
} //增删改
#region 增删改
public T AddEntity(T entity)
{
context.Set<T>().Add(entity);
context.SaveChanges();
return entity;
}
public bool DeleteEntity(T entity)
{
context.Entry<T>(entity).State = EntityState.Deleted;
return context.SaveChanges() > ;
}
public bool UpdateEntity(T entity)
{
context.Entry<T>(entity).State = EntityState.Modified;
return context.SaveChanges() > ;
}
#endregion
}

然后,在UserDal中的代码就可以注释掉了,直接让UserDal继承BaseDal就可以了,其他的XXXDal也是如此:

  public  class UserDal:BaseDal<Users>

2.在IofPf.Bll中编写业务逻辑层代码

在业务逻辑层中新建UserService.cs文件,然后书写一个添加数据的方法:

 public class UserService
{
UserDal userDal = new UserDal();//这个地方问题严重
public Users AddUser(Users user)
{
userDal.AddEntity(user);
return user;
}
}

好了,问题又来了,又到了一个要解耦的地方。

UserDal userDal = new UserDal();//这个地方问题严重

着重要讲的是这一句:

(1)首先,Bll层(UserService)中直接用了Dal层中的类(UserDal),这使得两层之间的联系很紧,耦合度太高,只要UserDal有任何变化,那么Bll层就要进行相应的改动。

改进1:在Dal层和Bll层之间添加接口层IDal,以后调用XXXDal的时候,使用IXXXDal进行调用,这样就用接口层把两个层隔离开来了:

具体做法:

在IotPf.IDal下新建接口文件IUserDal.cs,然后让UserDal继承IUserDal,当然,BaseDal的接口也是同理,下面给出代码如下:

IBaseDal:

  public interface IBaseDal<T> where T : class,new()
{
IQueryable<T> GetEntityByLambda(Expression<Func<T, bool>> wherelambda); T AddEntity(T entity); bool DeleteEntity(T entity); bool UpdateEntity(T entity);
}

IUserDal:

 public interface IUserDal:IBaseDal<Users>
{ }

UserDal和BaseDal都要继承IUserDal和IBaseDal才行哦,不然调不动的呢。

使用接口后则调用过程变为这样:

IUserDal userDal = new UserDal();

其实像这样写问题仍然蛮严重的。为啥呢?且看第二个问题:

(2)我们肯定不止一个文件会用到UserDal吧,实际上很多个文件都会用到UserDal。但是,如果有一天,我的Dal要由EF写的UserDal换为NH写的NHUserDal,那可怎么整呢,我难道要在每个用到UserDal的文件里分别去把new UserDal() 换为 new NHUserDal()?,显然不啊,和上面那个上下文的类似,我们新建一个类,把new UserDal的操作单独取出来,放在一个单独的方法中,这样只需要改一个地方就可以了。

具体做法:

在IotPf.Factory下新建AbstractFactory.cs,然后在里面添加如下代码:

  public  class AbstractFactory
{
public static IUserDal GetCurrentUserDal()
{
return new UserDal();
}
}

然后调用过程进一步改进为如下:

   IUserDal userDal = AbstractFactory.GetCurrentUserDal();

这样就要灵活多了。

这种做法其实就是工厂的概念啦。

但是,这样仍然不完美的啦,是不是很恼火,怎么这么麻烦,还能不能愉快的写代码了。哈哈哈,莫慌,麻烦是麻烦,但这种思想还是很牛逼的,好处多多哇。下面看问题:

(3)我接下来说 AbstractFactory.cs里面的不足之处。什么不足之处呢?

现在我只写了一个GetCurrentUserDal() 对吧,这改起来倒是方便了,但是做项目不可能只有一个UserDal啊,以后肯定会有 ADal啊,BDal,CDal等各种Dal,一旦EF变为NH,那在这个工厂里不是又要改一堆名字了吗?这也太烦了啊。那怎么弄呢?看下面:

我们可以把所使用的数据库操作方式(EF还是NH还是Ado.net)写进一个配置文件里面。假设我现在有两种方式操作数据库,EF和NH,一种操作数据库的方法写在项目EFDal下,另一种写在NHDal项目下,然后让两个项目下各个操作方法的名字保持一致。如果要用EF操作,那就在配置文件中引用 EFDal,如果用NH操作,那就在配置文件中引用NHDal,这样就可以切换自如了,是不是很方便呢,哈哈,确实挺溜的呀。

具体做法:

首先,在Ui下的web.config文件中此处添加如下代码:

代码:

 <add key="DalAssemblyName" value="IotPf.Dal"/>

然后在 AbstractFactory.cs下添加如下代码:

  //配置文件设置
public static string AssemblyName = System.Configuration.ConfigurationManager.AppSettings["DalAssemblyName"];
public static IUserDal GetUserDal()
{
//配置文件设置 ,移到方法外面,会被多个GetXXXDal使用
// string AssemblyName = System.Configuration.ConfigurationManager.AppSettings["DalAssemblyName"];
return Assembly.Load(AssemblyName).CreateInstance(AssemblyName + ".UserDal") as IUserDal;
}

这里因为使用了配置文件,所以不要忘记添加下面这个引用哦:

这就是所谓的 抽象工厂的概念啦。

就像我现在用的是IotPf.Dal,那我在配置文件里的value那个地方就写IotPf.Dal,以后如果我需要用IotPf.XXXDal,那我就把value改为IotPf.XXXDal就好了。

3.下面我们来讲一下DbSession

DbSession是啥呢?说起DbSession那就要从上面的UserService接着讲啦。下面要说一下 上下文的 context.SaveChanges()了。

我们应该都知道的,如果我们操作上下文对数据库进行了 增、删、改的操作,那么操作结束后需要有一个 context.SaveChanges()的操作,用来把对实体的修改保存到数据库中。目前,我们这个操作是写在UserDal中的。但是,这样做有一个问题,什么问题呢,我们先看一下下面这段代码:

 IUserDal userDal = AbstractFactory.GetUserDal();
public Users AddUser(Users user)
{
userDal.AddEntity(user);
userDal.DeleteEntity(user);
userDal.UpdateEntity(user);
return user;
}

这段代码中调用了三个UserDal中的方法,分别对数据库进行了三次不同的操作,每次操作之后相应的都会执行一次context.SaveChanges()的操作,也就是说与数据库交互了三次。有没有觉得三次有点多了呢,明明可以更少的呀,以后如果代码量大了,可能会交互更多次,那性能就很差了呀。这里呀,我们明明可以只交互一次就搞定的呀,怎么做呢,我们可以在把SaveChanges()的操作从UserDal中迁移到UserService中的呀,在UserDal中的每个方法先不写context.SaveChanges()的操作,而是在UserService中把增删改这单个操作一起完成之后再统一进行提交,那岂不是更好吗。就像下面这样:

(此代码仅说明统一提交的意思,不是实际程序中的写法,看这个的同学不要粘这段代码)

  IUserDal userDal = AbstractFactory.GetUserDal();
public Users AddUser(Users user)
{
userDal.AddEntity(user);
userDal.DeleteEntity(user);
userDal.UpdateEntity(user);
        context.SaveChanges();//统一提交
return user;
}

下面具体来讲做法:

首先,在IotPf.Factory下新建类 DbSession.cs,然后在里面编写如下代码:

   public  class DbSession
{
//声明UserDal
public IUserDal UserDal
{
get
{
return AbstractFactory.GetUserDal();
}
}
//保存实体
public int SaveChanges()
{
return DbContextFactory.GetCurrentDbContext().SaveChanges();
}
}

看到没,声明UserDal的操作现在搬到DbSession中了。

然后,UserService.cs现在变成下面这种写法:

  public class UserService
{ //IUserDal userDal = AbstractFactory.GetUserDal();
DbSession dbSession = new DbSession();
public Users AddUser(Users user)
{
dbSession.UserDal.AddEntity(user);
dbSession.UserDal.DeleteEntity(user);
dbSession.UserDal.UpdateEntity(user);
dbSession.SaveChanges();
return user;
}
}

保存操作已经不再由Dal层控制了,而是提交到Bll层,由Bll层控制。当然,不要忘记回到Dal层,把原来代码中的SaveChanges操作去掉:去掉后代码如下:

  public  class BaseDal<T> where T : class , new()
{
//实例化上下文
DbContext context = DbContextFactory.GetCurrentDbContext();
//使用lambda条件进行查询
public IQueryable<T> GetEntityByLambda(Expression<Func<T,bool>> wherelambda)
{
return context.Set<T>().Where(wherelambda).AsQueryable();
} //增删改
#region 增删改
public T AddEntity(T entity)
{
context.Set<T>().Add(entity);
// context.SaveChanges();
return entity;
}
public bool DeleteEntity(T entity)
{
context.Entry<T>(entity).State = EntityState.Deleted;
// return context.SaveChanges() > 0;
return true;
}
public bool UpdateEntity(T entity)
{
context.Entry<T>(entity).State = EntityState.Modified;
// return context.SaveChanges() > 0;
return true;
}
#endregion
}

现在是不是就好多了,以后与数据库交互的次数就大大减少了,这样性能应该能提高不少吧,哈哈。

紧接着,我们需要将DbSession和Bll层进行隔离,也就是这个操作:

现在应该已经轻车熟路了,先新建接口层 IDbSession.cs ,然后新建DbSessionFactory.cs,下面给出代码:

IDbSession.cs

  public interface IDbSession
{
IUserDal UserDal { get; }
int SaveChanges();
}

DbSessionFactory.cs:

  public static IDbSession GetCurrentDbSession()
{
IDbSession dbSession = CallContext.GetData("DbSession") as IDbSession;
if (dbSession == null)
{
dbSession = new DbSession();
CallContext.SetData("DbSession", dbSession);
}
return dbSession;
}

现在UserService.cs中的代码就变成这样:

     IDbSession dbSession = DbSessionFactory.GetCurrentDbSession();
public Users AddUser(Users user)
{
dbSession.UserDal.AddEntity(user);
dbSession.UserDal.DeleteEntity(user);
dbSession.UserDal.UpdateEntity(user);
dbSession.SaveChanges();
return user;
}

写到这里,数据访问层Dal和业务逻辑成Bll之间的解耦基本已经说完了,我感觉应该还是讲的比较清楚的了哈。

这个框架搭建的前半部分就已经讲完了,后面关于业务逻辑层Bll和展示层UI之间的系列操作,我留到下一篇讲啦,哈哈,一下子写完我自己hold不住,你估计也看不下去了吧。

下面总结一下哈:

本篇内容扯了那么长,我也真是够有尿性的了,总结起来其实也就几个内容而已啦:

(1)使用接口层进行层与层之间的隔离;

(2)对重复多次使用的方法进行基类封装;

(3)使用工厂的概念,对数据库操作方法进行配置,便于应对数据库的更换,提高框架灵活性;

(4)使用DbSession将数据库保存操作的权限有Dal层提交到业务逻辑层,减少与数据库交互次数,提高代码性能;

下一篇将介绍spring.net的使用,虽然我自己也不咋会 ,但还是把自己理解的写出来吧,以写代练,加深理解,大神们不要见笑啊。

我的eMail:3074596466@qq.com

完成框架代码就不往上贴了哈,有需要的同学可以给我发邮件索取。

明天就是国庆节啦,提前祝大家国庆节快乐,祝祖国繁荣昌盛!

asp.net mvc 简单项目框架的搭建过程(一)对Bll层和Dal层进行充分解耦的更多相关文章

  1. asp.net mvc 简单项目框架的搭建(二)—— Spring.Net在Mvc中的简单应用

    摘要:上篇写了如何搭建一个简单项目框架的上部分,讲了关于Dal和Bll之间解耦的相关知识,这篇来把后i面的部分说一说. 上篇讲到DbSession,现在接着往下讲. 首先,还是把一些类似的操作完善一下 ...

  2. ASP.NET MVC企业级项目框架

    ASP.NET MVC企业级项目框架 MVC项目搭建笔记---- 项目框架采用ASP.NET MVC+Entity Framwork+Spring.Net等技术搭建,搭建过程内容比较多,结合了抽象工厂 ...

  3. ASP.NET MVC 简单介绍①

    ASP.NET  MVC 简单介绍① 只做了重要描述,内容出自菜鸟教程网站内容. 目录 1布局 2HTML 帮助器 3.Razor 语法 4.添加样式 5.Layout 6. Controllers ...

  4. angular2+typescript在asp.net MVC Web项目上的实现

    网上现在还没有关于angular2+typescript在asp.net mvc web项目上的实现的系统介绍,这里我也只是探索到了一个简单的方式,还有很多问题没能解决.但是能有个好的开头也值得记录一 ...

  5. 使用Visual Studio 2015 开发ASP.NET MVC 5 项目部署到Mono/Jexus

    最新的Mono 4.4已经支持运行asp.net mvc5项目,有的同学听了这句话就兴高采烈的拿起Visual Studio 2015创建了一个mvc 5的项目,然后部署到Mono上,浏览下发现一堆错 ...

  6. 用开源 ASP.NET MVC 程序 Bonobo Git Server 搭建 Git 服务器(转)

    用开源 ASP.NET MVC 程序 Bonobo Git Server 搭建 Git 服务器   现在不用Git,都不好意思说自己是程序员. 当你想用Git,而源代码服务器是Windows系统时,你 ...

  7. 项目一:项目第二天 Jquery ztree使用展示菜单数据 2、 基础设置需求分析 3、 搭建项目框架环境--ssh(复习) 4、 SpringData-JPA持久层入门案例(重点) 5、 Easyui menubutton菜单按钮使用 6、 Easyui messager消息框使用

    1. Jquery ztree使用展示菜单数据 2. 基础设置需求分析 3. 搭建项目框架环境--ssh(复习) 4. SpringData-JPA持久层入门案例(重点) 5. Easyui menu ...

  8. ASP.NET MVC 5项目

    图文详解远程部署ASP.NET MVC 5项目   话外篇: 由于感觉自己的机器比较慢,配置不好,所以最近想把之前的项目部署到实验室的服务器上,但是由于常不在实验室,所以在想能不能远程部署.因此今天专 ...

  9. asp.net mvc 4 项目升级到 asp.net mvc5

    一.开始 1.打开或新建asp.net mvc 4项目 2.修改 global.asax文件 原: WebApiConfig.Register(GlobalConfiguration.Configur ...

随机推荐

  1. Feature Preprocessing on Kaggle

    刚入手data science, 想着自己玩一玩kaggle,玩了新手Titanic和House Price的 项目, 觉得基本的baseline还是可以写出来,但是具体到一些细节,以至于到能拿到的出 ...

  2. solr+jieba结巴分词

    为什么选择结巴分词 分词效率高 词料库构建时使用的是jieba (python) 结巴分词Java版本 下载 git clone https://github.com/huaban/jieba-ana ...

  3. 毕业样本=[威尔士大学毕业证书]UWIC原件一模一样证书

    威尔士大学毕业证[微/Q:2544033233◆WeChat:CC6669834]UC毕业证书/联系人Alice[查看点击百度快照查看][留信网学历认证&博士&硕士&海归&am ...

  4. Python+Appium 获取 toast 文本值方法的封装

    获取toast内容方法封装如下: def get_Toast(self,message): #查找toast值 ''' method explain:查找toast的值,与find_Toast实现方法 ...

  5. 自学java难吗?一个JAVA学习者应该具备的素质

    无论是在校的学生也好,还是转行的也好,如今学JAVA开发的人越来越多,造成了如今新手越来越多,有人说前端饱和了,JAVA饱和了,JAVA才刚开始以一种好的势头发展就饱和了.我也是无语,一般说饱和的人, ...

  6. 企业移动应用和Smobiler

    www.smobiler.com     什么是企业移动应用?     能够通过一种方式来为客户.合作伙伴和员工交付信息和服务,从而帮助其增加收入,提高业务敏捷性和生产力的移动端产品,我们称之为企业移 ...

  7. 包装类及 LeetCode 每日一题

    1.包装类与创建对象 Java 为8大数据类型都提供了相应的包装类,并提供属性和方法,更方便的操作基本数据类型.包装类位于java.lang包中. 对于这几种类型的基本数据,都有相似的方法实现基本数据 ...

  8. Java之品优购课程讲义_day06(7)

    商品录入[SKU 商品信息]5.1 需求分析 基于上一步我们完成的规格选择,根据选择的规格录入商品的 SKU 信息,当用户选择相应的规格,下面的 SKU 列表就会自动生成,如下图:实现思路:实现思路: ...

  9. Spring Boot 入门(六):集成 treetable 和 zTree 实现树形图

    本篇文章是接着Spring Boot 入门(五):集成 AOP 进行日志管理写的,主要集成了树形图,在部门列表或者权限列表中,树形图经常被用上.主要是根据相应的 API 凭借 html 字符串 1.t ...

  10. Oracle数据库升级注意事项

    1 备份配置参数 数据库升级前的配置参数要备份,如PGA大小 这样数据库升级后还可以升级前的配置,而不至于使用安装升级时的默认配置 2 检查版本兼容 确认数据库升级后是否对生产环境上的代码有影响,如果 ...