温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何配置ABP框架使用对象映射

发布时间:2022-03-30 09:02:12 来源:亿速云 阅读:323 作者:小新 栏目:开发技术

小编给大家分享一下如何配置ABP框架使用对象映射,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

    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)
                        });

    以上是“如何配置ABP框架使用对象映射”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    abp
    AI