欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

abp(net core)+easyui+efcore仓储系统——创建应用服务(五)

程序员文章站 2022-05-15 13:21:49
在上一篇文章中学习了ABP的仓储(Repository)功能,Repository对数据库进行增删改查操作。在这一篇文章中我们主要了解应用服务层。 应用服务用于将领域(业务)逻辑暴露给展现层。展现层通过传入DTO(数据传输对象)参数来调用应用服务,而应用服务通过领域对象来执行相应的业务逻辑并且将DT... ......

abp(net core)+easyui+efcore仓储系统目录

abp(net core)+easyui+efcore仓储系统——abp总体介绍(一)

abp(net core)+easyui+efcore仓储系统——解决方案介绍(二)

abp(net core)+easyui+efcore仓储系统——领域层创建实体(三)

 abp(net core)+easyui+efcore仓储系统——定义仓储并实现 (四)

 

      在上一篇文章中学习了abp的仓储(repository)功能,repository对数据库进行增删改查操作。在这一篇文章中我们主要了解应用服务层。

一、解释下应用服务层

     应用服务用于将领域(业务)逻辑暴露给展现层。展现层通过传入dto(数据传输对象)参数来调用应用服务,而应用服务通过领域对象来执行相应的业务逻辑并且将dto返回给展现层。因此,展现层和领域层将被完全隔离开来。
以下几点,在创建应用服务时需要注意:

  1. 在abp中,一个应用服务需要实现iapplicationservice接口,最好的实践是针对每个应用服务都创建相应继承自iapplicationservice的接口。(通过继承该接口,abp会自动帮助依赖注入)
  2. abp为iapplicationservice提供了默认的实现applicationservice,该基类提供了方便的日志记录和本地化功能。实现应用服务的时候继承自applicationservice并实现定义的接口即可。
  3. abp中,一个应用服务方法默认是一个工作单元(unit of work)。abp针对uow模式自动进行数据库的连接及事务管理,且会自动保存数据修改。

二、定义应用服务接口需要用到的dto

    1. 在visual studio 2017的“解决方案资源管理器”中,右键单击“abp.tplms.application”项目。 选择“添加” > “新建文件夹”。

    2.将文件夹命名为“modules”。

    3. 右键单击“modules”文件夹,选择“添加” > “新建文件夹”。将文件夹重命名为“dto”。如下图。

 abp(net core)+easyui+efcore仓储系统——创建应用服务(五)

      4. 右键单击“dto”文件夹,然后选择“添加” > “类”。 将类命名为 moduledto,然后选择“添加”。代码如下。

using abp.application.services.dto;
using abp.automapper;
using abp.tplms.entitys;
using system;
using system.collections.generic;
using system.text;
namespace abp.tplms.modules.dto
{
    [automapfrom(typeof(module))]
    public class moduledto:entitydto<long>
    {
        public string displayname { get; set; }
        public string name { get; set; }      

        public string url { get; set; }       
        public string hotkey { get; set; }
        public int parentid { get; set; }
        public bool requiresauthentication { get; set; }
        public bool isautoexpand { get; set; }       
        public string iconname { get; set; }
        public int status { get; set; }
        public string parentname { get; set; }    

        public string requiredpermissionname { get; set; }
        public int sortno { get; set; }   
    }
}
  • 为了在页面上展示模块信息,moduledto被用来将模块数据传递到基础设施层。
  • moduledto继承自 entitydto<long>.跟在领域层定义的module类一样具有一些相同属性。
  • [automapfrom(typeof(module))]用来创建从module类到moduledto的映射.使用这种方法。你可以将module对象自动转换成moduledto对象(而不是手动复制所有的属性)。

      5. 右键单击“dto”文件夹,然后选择“添加” > “类”。 将类命名为 createupdatemoduledto ,然后选择“添加”。代码如下。

using abp.application.services.dto;
using system;
using system.collections.generic;
using system.componentmodel.dataannotations;
using system.text; 

namespace abp.tplms.modules.dto
{
   public  class createupdatemoduledto : entitydto<long>
    {

        public const int maxlength = 255;

        [required]
        [stringlength(maxlength)]
        public string displayname { get; set; }

        [required]
        [stringlength(maxlength)]
        public string name { get; set; }

        [required]
        [stringlength(maxlength)]
        public string url { get; set; }

        [stringlength(maxlength)]
        public string hotkey { get; set; }
        public int parentid { get; set; }
        public bool requiresauthentication { get; set; }

        public bool isautoexpand { get; set; }

        [stringlength(maxlength)]
        public string iconname { get; set; }

        public int status { get; set; }

        [required]
        [stringlength(maxlength)]
        public string parentname { get; set; }

        [stringlength(maxlength)]
        public string requiredpermissionname { get; set; }
        public int sortno { get; set; }    
    }
}
  • 这个dto类在创建和更新模块信息的时候被使用,用来从页面获取模块信息。
  • 类中的属性定义了数据注解(如[required])用来定义有效性验证。abp会自动校验dto的数据有效性。

  6. 为什么需要通过dto进行数据传输?

     一般来说,使用dto进行数据传输具有以下好处。

  • 数据隐藏
  • 序列化和延迟加载问题
  • abp对dto提供了约定类以支持验证
  • 参数或返回值改变,通过dto方便扩展
  • dto类被用来在 基础设施层 和 应用层 传递数据.

  7.dto规范 (灵活应用)

  • abp建议命名输入/输出参数为:methodnameinput和methodnameoutput
  • 并为每个应用服务方法定义单独的输入和输出dto(如果为每个方法的输入输出都定义一个dto,那将有一个庞大的dto类需要定义维护。一般通过定义一个公用的dto进行共用)
  • 即使你的方法只接受/返回一个参数,也最好是创建一个dto类
  • 一般会在对应实体的应用服务文件夹下新建dtos文件夹来管理dto类。

      定义完dto,是不是脑袋有个疑问,我在用dto在展现层与应用服务层进行数据传输,但最终这些dto都需要转换为实体才能与数据库直接打交道啊。如果每个dto都要自己手动去转换成对应实体,这个工作量也是不可小觑啊。
聪明如你,你肯定会想肯定有什么方法来减少这个工作量。

三、使用automapper自动映射dto与实体

    1.简要介绍automapper

    开始之前,如果对automapper不是很了解,建议看下这篇文章automapper小结

     automapper的使用步骤,简单总结下:

  • 创建映射规则(mapper.createmap<source, destination>();)
  • 类型映射转换(mapper.map<source,destination>(sourcemodel))

     在abp中有两种方式创建映射规则:

  • 特性数据注解方式:
    • automapfrom、automapto 特性创建单向映射
    • automap 特性创建双向映射
  • 代码创建映射规则:
    • mapper.createmap<source, destination>();

     2.为module实体相关的dto定义映射规则

      moduledto、createupdatemoduledto中的属性名与module实体的属性命名一致,且只需要从dto映射到实体,不需要反向映射。所以通过automapto创建单向映射即可。

  [automapto(typeof(module))] //定义单向映射
    public class moduledto:entitydto<long>
{

      ...

}

     [automapto(typeof(module))] //定义单向映射
    public  class createupdatemoduledto : entitydto<long>
    {

      ...

    }

 

四、定义imoduleappservice接口

   1. 右键单击“dto”文件夹,然后选择“添加” > “新建项”,在弹出对话框中选择“接口”。为应用服务定义一个名为 imoduleappservice 的接口。代码如下。

 using abp.application.services;
using abp.application.services.dto;
using abp.tplms.modules.dto;
using system;
using system.collections.generic;
using system.text;
using system.threading.tasks; 

namespace abp.tplms.modules
{

    public interface imoduleappservice : iapplicationservice
    {

        task createasync(createupdatemoduledto input);
        task updateasync(createupdatemoduledto input);
        task<listresultdto<moduledto>> getallasync();
        task  deleteasync(int id);
        void delete(int id);
    }
}

      从上面的代码中我们仔细看一下方法的参数及返回值,大家可能会发现并未直接使用module实体对象。这是为什么呢?因为展现层与应用服务层是通过data transfer object(dto)进行数据传输。

五、实现imoduleappservice

     对于具体的业务来讲,只是简单的增删该查,实现起来就很简单了。代码如下:

using abp.application.services;
using abp.application.services.dto;
using abp.domain.repositories;
using abp.tplms.entitys;
using abp.tplms.modules.dto;
using automapper;
using system;
using system.collections.generic;
using system.text;
using system.threading.tasks; 

namespace abp.tplms.modules
{
    public class moduleappservice : applicationservice, imoduleappservice
{

        private readonly irepository<module> _modulerepository;

        public moduleappservice(irepository<module> modulerepository)
        {

            _modulerepository = modulerepository;
        }

        public task createasync(createupdatemoduledto input)
        {
            var module =  mapper.map<module>(input);
            return _modulerepository.insertasync(module);
        }

        public task updateasync(createupdatemoduledto input)
        {           
           var module = mapper.map<module>(input);
            return _modulerepository.updateasync(module);
        }

        public async task<listresultdto<moduledto>> getallasync()
        {
            var books = await _modulerepository.getalllistasync();

            return new listresultdto<moduledto>(objectmapper.map<list<moduledto>>(books));          

        }

       public async task deleteasync(int id)
        {
             await _modulerepository.deleteasync(id);         

        }

        public  void delete(int id)
        {
             _modulerepository.delete(id);

        }

    }

}