配置ABP框架使用对象映射

目录
  • DTO和实体
    • 实体
    • DTO
  • 麻烦的映射
  • AutoMapper 集成
  • IObjectMapper/ObjectMapper
  • 对象拓展

DTO和实体

实体

实体是领域驱动设计(Domain Driven Design)中的概念,实体通常一一映射某些对象的固有属性,最常使用的是关系型数据库中的表。

在 ABP 中,实体位于领域层中,实体类需要实现 IEntity<TKey> 接口或继承 Entity<TKey> 基类,示例如下:

public class Book : Entity<Guid>
{
    public string Name { get; set; }

    public float Price { get; set; }
}

DTO

数据传输对象(Data Transfer Object),作为数据传输过程中的数据模型,用于在应用层和表示层之间传输数据。

在 ABP 中,DTO 位于应用服务层,即本系列文章示例源码中的 AbpBase.Application 项目。

通常表示层或其它类型的客户端调用应用服务时,将 DTO 作为参数传递,它使用领域对象(实体)执行某些特定的业务逻辑,并将 DTO (跟传入的 DTO 不是同一个)返回到表示层中,因此表示层与领域层完全隔离。

DTO 类 可能会跟 实体类的字段/属性高度相似,为每个服务的每个方法创建 DTO 类可能会很枯燥且费时间。

ABP 的 DTO 类示例如下:

    public class ProductDto : EntityDto<Guid>
    {
        public string Name { get; set; }
        //...
    }

麻烦的映射

前面提到,领域层和应用服务层是要隔离的,例如以下伪代码:

class HomeController
{
    AddService _service;

    [HttpPost]
    public int AddEquip(EquipDto dto)
    {
        return _service.Add(dto).Id;
    }
}

class AddService
{
    DataContext _context;
    EquipDto Add(EquipDto dto)
    {
        Equip equip = new Equip()
        {
          Name = dto.Name;
        };
        _context.Equip.Add(equip);
        _context.SaveChange();
        dto.Id = equip.Id;
        return dto;
    }
}

class EquipDto
{
    int Id;
    string Name;
}

----------

class Equip
{
    int Id;
    string Name;
}

这样每次都需要手动为 DTO 类和 实体类手动对字段赋值映射,当一个实体有数十个字段时,写出的代码会很冗长,而且容易忽略了某些字段,最终导致了 Bug。

大家都知道, AutoMapper 正好可以解决这个问题。

AutoMapper 集成

ABP 的 Volo.Abp.AutoMapper 模块封装或集成了 AutoMapper,所以我们正好使用模块,为 ABP 应用定义对象映射。

关于 AutoMapper 的使用,如何配置 Profile 等,笔者已经单独写到 浅入 AutoMapper,请点击链接另外学习 AutoMapper 的使用。

我们可以在 AbpBase.Application 项目中,新建 一个 AbpBaseApplicationAutoMapperProfile.cs 文件,这个文件用于实现 Profile 以及定义映射。将服务领域的映射集中到这个文件中;或者新建一个 Profiles 文件夹,在其中存放一些 Profile 类。

其内容如下:

    public class AbpBaseApplicationAutoMapperProfile:Profile
    {
        public AbpBaseApplicationAutoMapperProfile()
        {
            //base.CreateMap<MyEntity,MyDto>();
        }
    }

定义完毕后,需要配置 AutoMapper 依赖注入,可在 AbpBaseApplicationModule 的 ConfigureServices 方法中,增加以下代码:

            Configure<AbpAutoMapperOptions>(options =>
            {
                // 以模块为单位注册映射
                options.AddMaps<AbpBaseApplicationModule>();
                //// 以单个 Profiel 为单位注册映射
                //options.AddProfile<AbpBaseApplicationAutoMapperProfile>();
            });

在 Debug 阶段,我们担心项目改动代码时,新增的字段忘记了加入到映射配置中,或者其它情况,在 AutoMapper 中,我们可以使用 configuration.AssertConfigurationIsValid(); 来检查映射;在 ABP 中则可使用 validate: true 参数来开启检查。

            Configure<AbpAutoMapperOptions>(options =>
            {
                // 以模块为单位注册映射
                options.AddMaps<AbpBaseApplicationModule>(validate: true);
                //// 以单个 Profiel 为单位注册映射
                //options.AddProfile<AbpBaseApplicationAutoMapperProfile>(validate: true);
            });

IObjectMapper/ObjectMapper

在 AbpBase.Application 项目中,添加 Nuget 包,搜索 Volo.Abp.ObjectMapping 并下载相应的稳定版本。

IObjectMapper 有两个,一个是 AutoMapper 的接口,一个是 Volo.Abp.ObjectMapping 的 泛型接口。

AutoMapper 的 IObjectMapper 不好用,所以别用;用 Volo.Abp.ObjectMapping 的 IObjectMapper <接口>

ObjectMapper 是 AutoMapper 中的,我们可以直接在控制器等位置,使用 ObjectMapper 注入,然后通过 ObjectMapper 实例映射对象。

ObjectMapper 只有 .Map() 这个方法用得顺手。

        private readonly ObjectMapper<T1,T2> _mapper;
        public TestController(ObjectMapper<T1,T2> mapper)
        {
            _mapper = mapper;

            // ... 使用示例
            _ = mapper.Map<T1> ();
        }

也可以通过依赖注入使用 IObjectMapper 接口。

但是因为 ObjectMapper 是泛型类,每种类型的 DTO 都要注入一次的话,会很麻烦,因此这种方案也可以抛弃。

而 泛型的 IObjectMapper<TModule> 是一个抽象,我们使用 IObjectMapper<TModule> 做依赖注入的话,后续如果替换为别的对象映射框架,则不需要修改原有代码即可完成替代。而且 IObjectMapper<TModule> 比较舒服。

使用示例:

        private readonly IObjectMapper<AbpBaseApplicationModule> _mapper;
        public TestController(IObjectMapper<AbpBaseApplicationModule> mapper)
        {
            _mapper = mapper;

            // ... 使用示例
            _ = mapper.Map<...>();
        }

对象拓展

ABP框架提供了实体扩展系统允许你添加额外属性到已存在的对象 无需修改相关类。这句话是抄 ABP 官方文档的。

要支持对象拓展映射,则需要开启配置:

public class MyProfile : Profile
{
    public MyProfile()
    {
        CreateMap<User, UserDto>()
            .MapExtraProperties();
    }
}

时间有限,笔者这里只把官方文档的内容讲清楚,读者看完后,需要继续查阅官方文档,完整了解对象拓展。

ObjectExtensionManager 是一个拓展对象映射类,可以显式为类拓展一些额外的属性,这个类型在 Volo.Abp.ObjectMapping 中定义。

ObjectExtensionManager 是一个类型,但是我们不能直接 new 它,或者使用依赖注入,只能通过 ObjectExtensionManager.Instance 这个属性获取新的类型。我们无需关心它是用了啥设计模式,还是因为缓存之类的原因这样设计。

ObjectExtensionManager 有两种属性,其说明如下:

  • AddOrUpdate :是定义对象额外属性或更新对象额外属性的主要方法;
  • AddOrUpdateProperty:快捷地定义单个拓展属性的方法;

AddOrUpdateProperty 用于定义单个属性,AddOrUpdate 是一个容器,可以包含多个 AddOrUpdateProperty 

AddOrUpdateProperty 示例代码如下:

ObjectExtensionManager.Instance
    .AddOrUpdateProperty<TestA, string>("Name");
// 为 TestA 类添加了一个 G 属性

AddOrUpdate 的示例代码如下:

ObjectExtensionManager.Instance
    .AddOrUpdate<TestA>(options =>
        {
            options.AddOrUpdateProperty<string>("Name");
            options.AddOrUpdateProperty<bool>("Nice");
        }
    );

当然,我们还可以同时为多个类型同时定义一个额外的属性:

ObjectExtensionManager.Instance
    .AddOrUpdateProperty<string>(
        new[]
        {
            typeof(TestA),
            typeof(TestB),
            typeof(TestC)
        },
        "Name"
    );

如果需要定义多个属性,则可以使用 AddOrUpdate

            ObjectExtensionManager.Instance
                .AddOrUpdate(options =>
                {
                    options.AddOrUpdateProperty<string>("Name");
                }, new[]{
                    typeof(TestA),
                    typeof(TestB)
                    });

另外它还可以设置默认值、增加验证规则等,这些笔者就不再赘述,读者感兴趣可以点击链接进入官方文档查看。

https://docs.abp.io/zh-Hans/abp/latest/Object-Extensions#validation

到此这篇关于配置ABP框架使用对象映射的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 基于ABP框架实现数据字典开发

    在业务型的系统开发中,我们需要维护各种个样的类型,比如客户类型.客户行业.商品类型等等,这些类型往往信息量不多,并且相似度极高,如果采用一类型一表去设计,将会造成极大的工作量,通过将这部分类型的信息进行抽象,利用字段去存储类型区分,共用表结构,来达到兼容各种类型的功能,也就是设计一个数据字典,而对于一个具体类型来讲,是有多个选项的,比如性别,有男女,行业有工农商等,对于这部分选项,可抽象为某个类型下的字典项,即数据字典项. 一.数据字典设计思路 1.从客户类型.商品类型.行业类型来抽象考虑,首先

  • 基于ABP框架实现RBAC(角色访问控制)

    在业务系统需求规划过程中,通常对于诸如组织机构.用户和角色等这种基础功能,通常是将这部分功能规划到通用子域中,这也说明了,对于这部分功能来讲,是系统的基石,整个业务体系是建立于这部分基石之上的,当然,还有诸如多语言.设置管理.认证和授权等.对于这部分功能,ABP中存在这些概念,并且通过Module Zero模块完成了这些概念. 一.角色访问控制之RBAC RBAC:Role Based Access Control,基于角色的访问控制,这在目前大多数软件中来讲已经算得上是普遍应用了,最常见的结构

  • 搭建基础结构的ABP解决方案介绍

    目录 搭建项目基础结构 AbpBase.Domain.Shared 创建过程 AbpBase.Domain 创建过程 AbpBase.Application.Contracts 创建过程 AbpBase.Database 创建过程 AbpBase.Application 创建过程 AbpBase.HttpApi 创建过程 AbpBase.Web 创建过程 关于ABP和代码解疑 模块 [DependsOn] 配置服务和管道 模块如何关联 搭建项目基础结构 打开 VS 2019,创建一个解决方案,然

  • ABP框架中的事件总线功能介绍

    目录 事件总线 关于事件总线 为什么需要这个东西 事件总线创建过程 订阅事件 事件 发布事件 全局异常加入事件总线功能 创建事件 订阅事件 发布事件 测试 记录事件 事件总线 关于事件总线 ABP 中,为了方便进程间通讯,给开发者提供了一个叫 事件总线 的功能,事件总线分为 本地事件总线.分布式事件总线,本篇文章讲的是 本地事件总线,系列教程中暂时不考虑讲解 分布式事件总线. 事件总线 需要使用 Volo.Abp.EventBus 库,ABP 包中自带,不需要额外引入. 事件总线是通过 订阅-发

  • 为ABP框架添加基础集成服务

    目录 定义一个特性标记 全局统一消息格式 Http状态码 常用的请求结果 响应模型 全局异常拦截器 先说明一下 ApiResponseModel是抽象类 跨域请求 配置API服务 统一API模型验证消息 创建前 创建方式 创建后 补充:为什么需要统一格式 定义一个特性标记 这个标记用于标记一个枚举代表的信息. 在 AbpBase.Domain.Shared 项目,创建 Attributes目录,然后创建一个 SchemeNameAttribute 类,其内容如下: /// <summary>

  • 为ABP框架配置数据库

    目录 创建标准的EFCore数据库上下文 连接字符串 定义隔离的上下文 多数据库支持和配置 Freesql配置服务 在 AbpBase.Database 中,通过 Nuget 添加以下几个库: 版本都是 1.9.0-preview0917,你可以使用最新版本的. Freesql FreeSql.Provider.Sqlite FreeSql.Provider.SqlServer FreeSql.Provider.MySql 创建标准的 EFCore 数据库上下文 在 ABP 中,EFCore 上

  • 为ABP框架增加日志组件与依赖注入服务

    目录 自动依赖注入 添加日志依赖 添加日志功能 依赖注入 自动依赖注入 在 AbpBase.Web 的 AbpBaseWebModule 中,添加一个函数: 此函数用于扫描模块中的服务,自动将其加入容器中,这样就不需要收到加入了. /// <summary> /// 自动扫描所有的服务并进行依赖注入 /// </summary> /// <param name="context"></param> private void Configu

  • 如何在Asp.Net Core中集成ABP Dapper

    在实际的项目中,除了集成ABP框架的EntityFrameworkCore以外,在有些特定的场景下不可避免地会使用一些SQL查询语句,一方面是由于现在的EntityFrameworkCore2.X有些问题没有解决,另外一方面是基于性能方面的考虑,在了解本篇内容之前,首先还是来看看官方文档来给出的说明. 按照官方的介绍整体可以分为下面的步骤:1 安装依赖包.2 添加DependsOn属性标签.3 Entity to Table Mapping. 4 Usage 通过上面的4个步骤我们就能够正常在A

  • 配置ABP框架使用对象映射

    目录 DTO和实体 实体 DTO 麻烦的映射 AutoMapper 集成 IObjectMapper/ObjectMapper 对象拓展 DTO和实体 实体 实体是领域驱动设计(Domain Driven Design)中的概念,实体通常一一映射某些对象的固有属性,最常使用的是关系型数据库中的表. 在 ABP 中,实体位于领域层中,实体类需要实现 IEntity<TKey> 接口或继承 Entity<TKey> 基类,示例如下: public class Book : Entity

  • 详解ABP框架中的日志管理和设置管理的基本配置

    日志管理 Server side(服务器端) ASP.NET Boilerplate使用Castle Windsor's logging facility日志记录工具,并且可以使用不同的日志类库,比如:Log4Net, NLog, Serilog... 等等.对于所有的日志类库,Castle提供了一个通用的接口来实现,我们可以很方便的处理各种特殊的日志库,而且当业务需要的时候,很容易替换日志组件. 译者注释:Castle是什么:Castle是针对.NET平台的一个开源项目,从数据访问框架ORM到

  • ABP框架的基础配置及依赖注入讲解

    配置ABP 配置是通过在自己模块的PreInitialize方法中来实现的 代码示例如下: public class SimpleTaskSystemModule : AbpModule { public override void PreInitialize() { //在你的应用中添加语言包,这个是英语和作者的土耳其语. Configuration.Localization.Languages.Add(new LanguageInfo("en", "English&quo

  • 基于ASP.NET MVC的ABP框架入门学习教程

    为什么使用ABP 我们近几年陆续开发了一些Web应用和桌面应用,需求或简单或复杂,实现或优雅或丑陋.一个基本的事实是:我们只是积累了一些经验或提高了对,NET的熟悉程度. 随着软件开发经验的不断增加,我们发现其实很多工作都是重复机械的,而且随着软件复杂度的不断提升,以往依靠经验来完成一些简单的增删改查的做法已经行不通了.特别是用户的要求越来越高,希望添加的功能越来多,目前这种开发模式,已经捉襟见肘.我很难想象如何在现有的模式下进行多系统的持续集成并添加一些新的特性. 开发一个系统时,我们不可避免

  • ABP框架的体系结构及模块系统讲解

    DDD分层 为了减少复杂性和提高代码的可重用性,采用分层架构是一种被广泛接受的技术. 为了实现分层的体系结构,ABP遵循DDD(领域驱动设计)的原则,将分为四个层次: 展现层(Presentation):提供一个用户界面,实现用户交互操作. 应用层(Application):进行展现层与领域层之间的协调,协调业务对象来执行特定的应用程序的任务.它不包含业务逻辑. 领域层(Domain):包括业务对象和业务规则,这是应用程序的核心层. 基础设施层(Infrastructure):提供通用技术来支持

  • ABP框架中的日志功能完全解析

    ASP.NET Boilerplate使用Castle Windsor's logging facility日志记录工具,并且可以使用不同的日志类库,比如:Log4Net, NLog, Serilog... 等等.对于所有的日志类库,Castle提供了一个通用的接口来实现,我们可以很方便的处理各种特殊的日志库,而且当业务需要的时候,很容易替换日志组件. 译者注释:Castle是什么:Castle是针对.NET平台的一个开源项目,从数据访问框架ORM到IOC容器,再到WEB层的MVC框架.AOP,

随机推荐