实战Angular2+web api增删改查 (一)

2023-11-04

Angular2是一个前端开发框架,在引入ts之后使得我们这些C#开发者能够更快的熟悉该框架,angular2开发首先要知道这是一个SPA(单页应用),我们要摆脱以往的asp.net中的MVC模式的固有思路,angular2开发重点是组件(Component),所以开发之前尤其要能清楚这个概念。

在与angular2配合使用的后端(RestFul)我采用的是基于asp.net的web api2.0,这也是目前比较流行的一种方式。我在webapi开发中在数据层使用的是基于NHibernate的Repository+UnitWork模式,自然也会用到依赖注入,我选的依赖注入工具是AutoFac。在前端与后端的数据传递使用DTO,为了方便,使用的是AutoMapper做数据映射。下面从底层开始,以一个简单实例演示整个过程。

领域模型

在建模时曾考虑使用EF6,目前也有很多关于EF6的争议就是EF中实际已包含了Repository和UnitOfWork模式,那么在使用EF时就不必再使用这种模式了,为了能够熟练这种模式我选用了NHibernate作为ORM框架。

数据实体类

public class TGroup : EntityBase {

        public TGroup() {

            Users = new List<TUser>();

        }

        public virtual string ID { getset; }

        public virtual string GROUPNAME { getset; }

        public virtual decimal? NORDER { getset; }

        public virtual string PARENTID { getset; }

        public virtual DateTime? CREATED { getset; }

        public virtual string GROUPTYPE { getset; }

        public virtual string GROUPCODE { getset; }

        public virtual IList<TUser> Users { getset; }

    }

数据实体类都继承于EntityBase,EntityBase是一个空的类,目前没有任何属性及方法,只是为了在使用Repositroy模式时方便,其实可以抽象出诸如ID这样的公共属性出来。

关系映射

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping assembly="URS.Data" namespace="URS.Data.Model" xmlns="urn:nhibernate-mapping-2.2">
  <class name="TGroup" table="T_GROUP" lazy="true" >
    <id name="ID" column="ID" />
    <property name="GROUPNAME">
      <column name="GROUPNAME" sql-type="VARCHAR2" not-null="false" />
    </property>
    <property name="NORDER">
      <column name="NORDER" sql-type="NUMBER" not-null="false" />
    </property>
    <property name="PARENTID">
      <column name="PARENTID" sql-type="VARCHAR2" not-null="false" />
    </property>
    <property name="CREATED">
      <column name="CREATED" sql-type="DATE" not-null="false" />
    </property>
    <property name="GROUPTYPE">
      <column name="GROUPTYPE" sql-type="VARCHAR2" not-null="false" />
    </property>
    <property name="GROUPCODE">
      <column name="GROUPCODE" sql-type="VARCHAR2" not-null="true" />
    </property>
    <bag name="Users" inverse="true" cascade="all">
      <key column="GROUPID" />
      <one-to-many class="TUser" />
    </bag>
  </class>
</hibernate-mapping>

在实体类中就可以看出这是一个一对多关系,TGroup包含了一个TUser集合,所以在映射时使用的bag中描绘了这个一对多关系,这里需要说明的是我所使用的是oracle数据库。

NHibernate配置

<?xml version="1.0" encoding="utf-8"?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory>
    <property name="connection.driver_class">NHibernate.Driver.OracleManagedDataClientDriver</property>
    <property name="connection.connection_string">User Id=urs;Password=urs;Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORA11G)))</property>
    <property name="show_sql">true</property>
    <property name="dialect">NHibernate.Dialect.Oracle10gDialect</property>
    <property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>
    <property name="current_session_context_class">call</property>
    <mapping assembly="URS.Data"/>
  </session-factory>
</hibernate-configuration>

这是一个使用oracle的odp的连接配置,这个配置文件需要放在WebAPI解决方案下

Repository模式

IRepository接口

public interface IRepository<TEntity> :IDependency where TEntity : EntityBase
    {
         TEntity Get(object id);
 
         IList<TEntity> GetAll();
         void Add( TEntity entity);
         void Update(TEntity entity);
         void Delete(TEntity entity);
         void Delete(object id);
       
 
        
    }

这里的IRepository接口只提取了部分通用的CURD操作,这里需要注意的是该接口继承了IDependency,这是为了我们下面使用依赖注入的一个空接口,下面会说到这样的目的。

Repository基类

public  class NHRepositoryBase<TEntity> : IRepository<TEntity> where TEntity : EntityBase
    {
        protected virtual ISession Session
        {
            get
            {
                return SessionBuilder.GetCurrentSession();
            }
        }
 
        public virtual TEntity Get(object id)
        {
            return Session.Get<TEntity>(id);
            
        }
 
        public virtual IList<TEntity> GetAll()
        {
            return Session.CreateCriteria<TEntity>()
                .List<TEntity>();
        }
 
        public virtual void Add(TEntity entity)
        {
            try
            {
                Session.Save(entity);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
 
        public virtual void Update(TEntity entity)
        {
            try
            {
                Session.SaveOrUpdate(entity);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
 
        public virtual void Delete(TEntity entity)
        {
            try
            {
                Session.Delete(entity);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
 
        public virtual void Delete(object id)
        {
            try
            {
                TEntity entity=this.Get(id);
                Session.Delete(entity);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }

由于我们使用的是NHibernate,所以我们需要一个全局的ISession,SessionBuilder是我封装的一个类,用来处理ISession,保障一个应用中只有一个ISession实例。

业务Repository

public class GroupRepository : NHRepositoryBase<TGroup>,IGroupRepository
    {
       
    }

由于Repository基类中包含了通用的CURD操作,所以这个GroupRepository 只需继承这个基类即可,如果还有其他操作或属性则再进一步抽象出IGroupRepository这里我还没打算加入其他操作所以IGroupRepository是个空的接口,以后也许会加入其他方法或属性。

UnitOfWork模式

unitofwork模式重点是处理事务,对变化的数据一次提交保证数据完整性。

IUnitOfWork接口

public interface IUnitOfWork : IDisposableIDependency
   {
       IRepository<TEntity> BaseRepository<TEntity>() where TEntity : EntityBase;
       void BeginTransaction();
       void Commit();
       void Rollback();
   }

这个接口同样也继承了IDependency,也是为了后面的依赖注入。在这个接口中我还定义了一个IRepository<TEntity>的属性,这是一个能够根据实体类来获取其对应的Repository。

UnitOfWork实现

public class NHUnitOfWork:IUnitOfWork
   {
       private ITransaction _transaction;
       private Hashtable _repositories;
       public  ISession Session
       {
           get
           {
               return SessionBuilder.GetCurrentSession();
           }
       }
 
       public NHUnitOfWork()
       {
           
       }
       public void BeginTransaction()
       {
           this._transaction = Session.BeginTransaction() ;
       }
 
       public void Commit()
       {
           try
           {
               // commit transaction if there is one active
               if (_transaction != null && _transaction.IsActive)
                   _transaction.Commit();
           }
           catch
           {
               // rollback if there was an exception
               if (_transaction != null && _transaction.IsActive)
                   _transaction.Rollback();
 
               throw;
           }
           //finally
           //{
           //    Session.Dispose();
           //}
       }
 
       public void Rollback()
       {
           //try
           {
               if (_transaction != null && _transaction.IsActive)
                   _transaction.Rollback();
           }
           //finally
           //{
           //    Session.Dispose();
           //}
       }
 
       public void Dispose()
       {
           Session.Dispose();
       }
 
       public IRepository<T> BaseRepository<T>() where T : EntityBase
       {
           if (_repositories == null)
               _repositories = new Hashtable();
 
           var type = typeof(T).Name;
 
           if (!_repositories.ContainsKey(type))
           {
               var repositoryType = typeof(NHRepositoryBase<>);
 
               var repositoryInstance =
                   Activator.CreateInstance(repositoryType
                           .MakeGenericType(typeof(T)));
 
               _repositories.Add(type, repositoryInstance);
           }
 
           return (IRepository<T>)_repositories[type];
       }
   }

这里使用了反射创建Repository实例,这里是创建的通用基类型的Repository实例,好处就是当我们在业务逻辑层使用UnitOfWork时如果是通用的操作,则不用注入Repository了,否则可能要构造中可能要注入很多业务Repository,比较麻烦,当然如果不是通用操作的话,还是要注入的,下面会讲到。

业务逻辑层应用

public class GroupService:IGroupService
    {
        private IUnitOfWork _unitOfWork;
        private IGroupRepository _groupRepository;
        public GroupService(IUnitOfWork unitOfWork,IGroupRepository groupRepository)
        {
            _unitOfWork = unitOfWork;
            _groupRepository = groupRepository;
        }
        public IList<TGroup> GetAll()
        {
            IRepository<TGroup> repo = _unitOfWork.BaseRepository<TGroup>();
            return repo.GetAll();
 
        }
 
        public TGroup GetByID(string id)
        {
            IRepository<TGroup> repo = _unitOfWork.BaseRepository<TGroup>();
            return repo.Get(id);
        }
 
        public void Add(TGroup entity)
        {
            _unitOfWork.BeginTransaction();
            IRepository<TGroup> repo = _unitOfWork.BaseRepository<TGroup>();
            repo.Add(entity);
            _unitOfWork.Commit();
        }
 
        public void Delete(string id)
        {
            _unitOfWork.BeginTransaction();
            IRepository<TGroup> repo = _unitOfWork.BaseRepository<TGroup>();
            repo.Delete(id);
            _unitOfWork.Commit();
        }
 
        public void Update(TGroup entity)
        {
            _unitOfWork.BeginTransaction();
            IRepository<TGroup> repo = _unitOfWork.BaseRepository<TGroup>();
            repo.Update(entity);
            _unitOfWork.Commit();
        }
    }

这里通过在构造函数中注入IUnitOfWork ,IGroupRepository这里可以看到,由于在本例中使用的都是通用的数据CURD,所以实际上IGroupRepository并没有使用,而实际使用的是IUnitOfWork中创建的IRepository<TGroup>,由于这个例子比较简单,如果是由复杂业务逻辑的话,那么需要在_unitOfWork.BeginTransaction()到_unitOfWork.Commit()之间完成业务处理即可保障数据提交的一致性,如果这中间有异常,IUnitOfWork会回滚,这就意味着要么全部提交,要不都不提交。

这里的GroupService继承了IGroupService而IGroupService也会继承IDependency下面将在WebApi的解决方案中介绍AutoFac的依赖注入使用方法。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

实战Angular2+web api增删改查 (一) 的相关文章

随机推荐

  • LeetCode-Python-54. 螺旋矩阵

    给定一个包含 m x n 个元素的矩阵 m 行 n 列 请按照顺时针螺旋顺序 返回矩阵中的所有元素 示例 1 输入 1 2 3 4 5 6 7 8 9 输出 1 2 3 6 9 8 7 4 5 示例 2 输入 1 2 3 4 5 6 7 8
  • 广州站

    12月2日 由阿里云 Serverless 团队主办的 云原生 Serverless 技术实践营 在广州顺利举行 本次活动面向所有企业技术人员 主打 沉浸式沙龙体验 6 小时搞定 Serverless 企业落地 活动当天 5 位阿里云技术讲
  • 80%白领危了!OpenAI发布GPT时代就业秘笈:34大铁饭碗保命

    导读 GPT 4发布没几天 OpenAI直接告诉所有人 GPTs是通用技术 80 的美国人的工作受到影响 想要保命 且看这34大 铁饭碗 前脚刚推出GPT 4 OpenAI后脚就发布了35页论文官宣 80 的美国人 都会受到AI的影响 研究
  • STM32“隐藏的定时器”-DWT

    01 前言 在之前的文章在 STM32延时函数的四种方法 使用定时器延时 在 如何测量代码运行时间 中提到使用定时器外设计算代码运行时间 文中提到这种方法的明显缺点就是需要占用一个定时器 一些MCU在特定应用场景下定时器外设资源是十分稀缺的
  • 信息安全大赛出的题目

    今天是信息安全大赛决赛的日期 可惜还要去市里培训 不能去现场观看 听说的做的一塌糊涂 也许是第一次举办这样的比赛 在校内还没有这样的氛围的缘故吧 中午打了电话 得知总分150左右的 最高的得了68分 我在反思 是我们把题目的难度没控制好 还
  • 华为OD机试 C++【最少步数】

    题目 你在一个一维的数轴上 起始位置为0 你每次只能走2步或3步 无论是向左还是向右 有时你可能需要走到负坐标上去 才能最终到达你的目标位置 任务 给定一个坐标点 找出到达那里的最小步数 输入 一个整数 n 表示目标坐标位置 1 lt n
  • Matter Project 入门 – Chip-tool 调试终端设备

    注意 本指南是对 Matter TE7 5 的投诉 请查看芯片工具 GitHub 页面 以获取任何最新更改 如果您没有遵循Matter 构建指南 您应该首先在您的 Raspberry Pi 4 上准备 Matter 环境 然后导航到 con
  • 二货小易有一个W*H的网格盒子,网格的行编号为0~H-1,网格的列编号为0~W-1。每个格子至多可以放一块蛋糕,任意两块蛋糕的欧几里得距离不能等于2。

    二货小易有一个W H的网格盒子 网格的行编号为 0到H 1 网格的列编号为 0到W 1 每个格子至多可以放一块蛋糕 任意两块蛋糕的欧几里得距离不能等于2 对于两个格子坐标 x1 y1 x2 y2 的欧几里得距离为 x1 x2 x1 x2 y
  • Idea: debug 跳出循环

    点击循环下面的某行代码 点击run to cusor按钮
  • RedHat Linux各版本汇总

    Linux的发行版本可以大体分为两类 一类是商业公司维护的发行版本 一类是社区组织维护的发行版本 前者以著名的Redhat RHEL 为代表 后者以Debian为代表 Redhat有两大 Linux产品系列 其一是免费的Fedora Cor
  • 关于tomcat7-maven-plugin插件的使用

    最近在学习黑马的淘淘项目 第一步是使用maven依赖进行环境搭建 其中使用到了tomcat7 maven plugin这个插件 视频中老师给的依赖大致是这样的
  • Java并发编程:Synchronized底层优化(偏向锁、轻量级锁)

    Java并发编程系列 Java 并发编程 核心理论 Java并发编程 Synchronized及其实现原理 Java并发编程 Synchronized底层优化 轻量级锁 偏向锁 Java 并发编程 线程间的协作 wait notify sl
  • sql中的排序函数dense_rank(),RANK()和row_number()

    dense rank RANK 和row number 是SQL中的排序函数 为方便后面的函数差异比对清晰直观 准备数据表如下 1 dense rank 函数语法 dense rank over order by 列名 desc asc D
  • requests 和flask豆瓣安装方法

    pip3 install requests i http pypi douban com simple trusted host pypi douban com pip3 install flask i http pypi douban c
  • SQL中的case when then else end语句的用法示例

    case具有两种格式 简单case函数和case搜索函数 简单case函数 case sex when 1 then 男 when 2 then 女 else 其他 end case搜索函数 case when sex 1 then 男 w
  • 【nginx】配置proxy_pass之后,响应变慢的问题

    背景 netstub项目中 使用openresty作为网关 proxy pass处理 配置如下 access lua中进行一些预处理 然后代理到目标服务 location access by lua file etc nginx conf
  • 第一章 pandas基础-学习笔记

    第一章 pandas基础 首先要导入对应的模块 import pandas as pd import numpy as np 一 文件的读取和写入 1 常见文件类型读取方法 读取之前先了解常用的对应参数 1 header None 表示第一
  • aoa定位算法matlab仿真,基于信号到达角度(AOA)的定位算法研究

    内容摘要 基于信号到达角度 AOA 的定位算法是一种常见的无线传感器网络节点自定位算法 算法通信开销低 定位精度较高 由于各种原因 估测的多个节点位置可能存在不可靠位置 提出了一种改进的基于信号到达角的定位方法 通过过滤误差较大的估计位置
  • 手写Promise核心代码

    1 框架构建 class Promise 定义状态并立即执行excutor函数 constructor 修改状态为fufilled resolve 修改状态为reject reject 根据excutor函数的结果执行对应的回调 then
  • 实战Angular2+web api增删改查 (一)

    Angular2是一个前端开发框架 在引入ts之后使得我们这些C 开发者能够更快的熟悉该框架 angular2开发首先要知道这是一个SPA 单页应用 我们要摆脱以往的asp net中的MVC模式的固有思路 angular2开发重点是组件 C