最近主导了一个电商系统的设计开发过程,包括前期分析设计,框架搭建,功能模块的具体开发(主要负责在线支付部分),成功上线后的部署维护,运维策略等等全过程。

虽然这个系统不是什么超大型的电商系统 数亿计的并发,但团队里的主要成员都有多年的开发经验以及电商的经验,系统设计方面还是麻雀虽小,但五脏俱全。

系统客户端有 ios , android,H5,微信小程序,后台方面用.net web api + sql server,图片资源的读写使用阿里云,缓存则自己搭建redis,支付方面既有使用一些第三方支付平台,也有和支付宝微信等。。。。  技术点很多,说实话,基本上一般应用系统开发用到的技术基本都用到了,也遇到了很多的坑。所以觉得把里面的代码整理归纳出来很有必要,对于以后的系统开发,特别同类项目的开发,很有借鉴意义。由于我没有参与前端的开发,所以这里主要以.nt 后台架构的讲述为主。

        由于是.nt  mvc web api,所以选择了 EF作为orm组件。程序分层架构分为: 数据层 DAL和 IDAL,业务层BLL和IBLL,Entity(实体定义),WebAPI,另外还建了一个Utility项目,用于容纳一些与业务无关并且可以复用的功能性代码以及第三方开源代码,另外还有两个单独的解决方案,一个名为thirdparty的web api项目, 用于和第三方平台的接口交互,包括向短信平台发送短信验证码,向阿里云上传图片,查询 快递单物流状态,向推送平台(极光,微信公众号)推送消息。另一个为windows服务程序,用于执行自动化工作任务。

下面分别讲述。

一、DAL。主要负责封装对EF的底层数据操作。其中有一段对EF 的DBContext 实现单例模式的代码,是我当时从网上摘抄下来的,代码如下

  1. public class DbContextFactory
  2. {
  3. public static WinLinkContext Create()
  4. {
  5. WinLinkContext dbContext = CallContext.GetData("DbContext") as WinLinkContext;
  6. if (dbContext == null)
  7. {
  8. dbContext = new WinLinkContext();
  9. CallContext.SetData("DbContext", dbContext);
  10. }
  11. return dbContext;
  12. }
  13. }

  其实我最初使用EF时,我记得官方文档都是提倡 dbcontext 是即用即销的,形如   (using WinLinkContext = new WinLinkContext() ){...} 那样,有必要把dbcontext只实例化一个并缓存下来,这样能提高性能和节省资源吗? 开始由于项目工期紧张,没有考虑太多,想着这是别人使用过的成熟代码,还是某大咖的博文例子,应该错不了。结果后来还是出现了问题。某同事a写日志处理模块的时候,也调用了这个 DbContextFactory.Create() ,本意是想把异常发生时的信息记录到数据库,但由于和业务代码公用一个dbcontext,问题就来了。比如某同事b写了几行  add/update EF的代码,接着又写了几行其他的代码, 还没执行 savechanges,但这几行其他代码出现bug,引发异常,于是日志捕捉到了,日志模块就进行使用ef进行插入日志信息,执行savechanges,这时重点来了 , 这个savechanges就会把整个dbcontext的更新内容提交到数据库了!于是连日志模块都报错了,而且错误提示是同事b的代码内容。当然也有读者会说日志模块应该独立开不应该和业务混在一起,确实后来我们也把它独立开了。但这个例子表明 dbcontext使用单例模式有很大问题,我认为还是应该遵循微软官方示例,即用即销,就算要缓存,至少每个模块独立开,不能整个应用使用唯一的一个。比如把上面的代码稍加变化,根据名称读写不同的dbcontext。

  1. public class DbContextFactory
  2. {
  3. public static WinLinkContext Create(string dbName)
  4. {
  5. WinLinkContext dbContext = CallContext.GetData(dbName) as WinLinkContext;
  6. if (dbContext == null)
  7. {
  8. dbContext = new WinLinkContext();
  9. CallContext.SetData(dbName, dbContext);
  10. }
  11. return dbContext;
  12. }
  13. }

另外还有一个BaseDAL的类,用于封装常规的增删改查以及分页等方法,代码大致如下(里面的db对象就是上文提到dbcontext):

  1. public T Add(T t)
  2. {
  3. return db.Set<T>().Add(t);
  4. }
  5.  
  6. public void Update(T t)
  7. {
  8. db.Set<T>().AddOrUpdate(t);
  9. }
  10.  
  11. public void Delete(T t)
  12. {
  13. db.Set<T>().Remove(t);
  14. }
  15. public bool Delete(string id)
  16. {
  17. var entity = db.Set<T>().Find(id);
  18. if (entity == null)
  19. {
  20. return false;
  21. }
  22. db.Set<T>().Remove(entity);
  23. return true;
  24. }
  25.  
  26. public int Delete(string[] ids)
  27. {
  28. foreach (var item in ids)
  29. {
  30. var entity = db.Set<T>().Find(item);//如果实体已经在内存中,那么就直接从内存拿,如果内存中跟踪实体没有,那么才查询数据库。
  31. db.Set<T>().Remove(entity);
  32. }
  33. return ids.Count();
  34. }
  35.  
  36. public T Find(Expression<Func<T, bool>> findLambda)
  37. {
  38. return db.Set<T>().FirstOrDefault(findLambda);
  39. }
  40.  
  41. public T Find(string id)
  42. {
  43. return db.Set<T>().Find(id);
  44. }
  45.  
  46. public IQueryable<T> Where(Expression<Func<T, bool>> whereLambda)
  47. {
  48. return db.Set<T>().Where(whereLambda);
  49. }
  50.  
  51. public IQueryable<T> GetByPage<Type>(int pageSize, int pageIndex, out int total, Expression<Func<T, bool>> whereLambda, Expression<Func<T, Type>> orderByLambda, bool isAsc)
  52. {
  53. var queryData = db.Set<T>().Where(whereLambda);
  54.  
  55. //是否升序
  56. if (isAsc)
  57. {
  58. queryData = queryData.OrderBy(orderByLambda);
  59. }
  60. else
  61. {
  62. queryData = queryData.OrderByDescending(orderByLambda);
  63. }
  64.  
  65. total = queryData.Count();
  66. if (total > )
  67. {
  68. if (pageIndex <= )
  69. {
  70. queryData = queryData.Take(pageSize);
  71. }
  72. else
  73. {
  74. queryData = queryData.Skip((pageIndex - ) * pageSize).Take(pageSize);
  75. }
  76.  
  77. }
  78.  
  79. return queryData;
  80. }

电商系统架构总结1(EF)的更多相关文章

  1. 电商系统架构总结2(Redis)

    二  Redis缓存 考虑到将来服务器的升级扩展,使用redis代替.net内置缓存是比较理想的选择.redis是非常成熟好用的缓存系统,安装配置非常简单,直接上官网下载安装包 安装启动就行了. 1 ...

  2. 电商系统架构总结4(webapi 版本控制)

    为了 顺利迭代升级,web api 在维护过程是不断升级的,但用户是不能强迫他们每次都跟随你去升级,这样会让用户不胜其烦.为了保证不同版本的客户端能同时兼容,在web api接口上加入版本控制就很有必 ...

  3. 电商系统架构总结3(webapi授权机制)

    三 Web API 授权方式 web api的客户端,包括 android,ios,h5,自然对访问权限要加上授权机制.对于h5,要求把h5站点和web api部署在同一个域名下,然后对web api ...

  4. 集DDD,TDD,SOLID,MVVM,DI,EF,Angularjs等于一身的.NET(C#)开源可扩展电商系统–Virto Commerce

    今天一大早来看到园友分享的福利<分享一个前后端分离方案源码-前端angularjs+requirejs+dhtmlx 后端asp.net webapi>,我也来分享一个吧.以下内容由笔者写 ...

  5. 电商系统的演变可以看出架构演变 Dubbo入门 远程过程调用 需要解决的问题

    Dubbo入门---搭建一个最简单的Demo框架 - CSDN博客 https://blog.csdn.net/noaman_wgs/article/details/70214612 Dubbo背景和 ...

  6. 属性 每秒10万吞吐 并发 架构 设计 58最核心的帖子中心服务IMC 类目服务 入口层是Java研发的,聚合层与检索层都是C语言研发的 电商系统里的SKU扩展服务

    小结: 1. 海量异构数据的存储问题 如何将不同品类,异构的数据统一存储起来呢? (1)全品类通用属性统一存储: (2)单品类特有属性,品类类型与通用属性json来进行存储: 2. 入口层是Java研 ...

  7. (1)dotnet开源电商系统-brnshop&brnMall 和老外开发的nopCommerce(dotnet两套电商来PK--第一篇)

    一直想做电商软件,但是实在不想学PHP了,所以前后关注了这两个开源电商系统.一个是国人出品的,一个据说是俄罗斯人写得(不知道对不对).目前两个开源软件都在学习了解中,以下的博文可能会涉及到这两套系统, ...

  8. 基于SpringBoot+MyBatis实现一套电商系统

    项目介绍 mall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现. 前台商城系统包含首页门户.商品推荐.商品搜索.商品展示.购物车.订单流程.会员中心 ...

  9. SpringBoot+Security+MyBatis+ES+MQ+Redis+Docker+Vue的电商系统

    今天鹏哥给大家推荐的项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现. 前台商城系统包含首页门户.商品推荐.商品搜索.商品展示.购物车.订单流程.会员中 ...

随机推荐

  1. c语言中如何通过二级指针来操作二维数组

    通过二级指针去访问二维数组需要先给二级指针分配等同于二维数组行数的一维数组指针,然后把二维数组的每行首地址赋值给对应位置的一维指针上.之后就可以通过二维指针直接访问了. 参考代码如下,可以看具体注释辅 ...

  2. Java 反射基础

    1.反射概念: Java运行时,动态获得类的信息以及动态调用对象的方法的功能. 在运行时判断任意一个对象所属的类 在运行时构造任意一个类的对象 在运行时判断任意一个类所具有的成员变量和方法 在运行时调 ...

  3. Qt中窗口退出事件

    窗口右上角的X按键会导致其在不给出任何提示的情况下直接退出, 当点击右上角的x按键时,会触发Qt中的一个事件处理函数:void QWidget::closeEvent ( QCloseEvent * ...

  4. Maven install报MojoFailureException

    [ERROR] 位置: 类 com.spark.test.JavaDirectKafkaWordCount [ERROR] /I:/TrueTimeControlOnSparkByJava/src/m ...

  5. mysql日常处理

    http://blog.csdn.net/zengxuewen2045/article/details/52349731 https://github.com/enmotplinux/On-Site- ...

  6. CentOS 7 firewalld vsftpd开放端口

    开放FTP端口的方法: 暂时开放 ftp 服务 firewall-cmd --add-service=ftp 1 永久开放 ftp 服务 firewall-cmd --add-service=ftp ...

  7. 一个OpenGL小程序

    发个没什么技术含量的文,最近准备通过opengl的学习来好好c++,于是找了网上的教程来搭建opengl的编写环境,建了个空项目,又找了个案例稍微改了改运行了下,还成,ok了~喜不自禁~ 贴个图: 代 ...

  8. Flask--异常处理

    异常处理: abort(404)-捕获HTTP抛出的统一状态码 @app.errorhandler-捕获全局异常错误码,捕获异常错误 @app.route("/demo4") de ...

  9. 函数,lambda函数,递归函数,内置函数(map,filter),装饰器

    1. 集合 主要作用: 去重 关系测试, 交集\差集\并集\反向(对称)差集 2. 元组 只读列表,只有count, index 2 个方法 作用:如果一些数据不想被人修改, 可以存成元组,比如身份证 ...

  10. 25天javaweb基础

    第一天(html) 表格标签,超链接标签,图片标签,排版标签,列表标签 第二天(css) 表单标签 第三天(JS) js语法 定时器(系统对象的定时器setinterval,js的定时器seTimeo ...