Web开发:使用Abp.AutoMapper进行实体映射的demo

目录

一、安装Nuget包

二、控制台程序Demo

1.文件目录

2.程序示例

(1)示例实体

(2)AutoMapperProfile.cs(映射规则)的配置

(3)使用映射(程序入口)

三、ABP框架Demo

(1)AutoMapperProfile.cs(映射规则)的配置

(2)ABP框架下实体映射的三种方式

四、常见配置

1.映射检查及双向映射

2.遍历修改

3.多字段映射写法

4.映射字段的忽略(含不可访问属性)

五、常见问题

1.类型映射失败

2.数据映射失败

3.映射语法报错

4.为什么需要写DTO?


一、安装Nuget包

二、控制台程序Demo

1.文件目录

2.程序示例

(1)示例实体


namespace ConsoleApp1
{
    public class Model
    {
    }
    public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }

    public class Teacher
    {
        public int Id { get; set; }
        public string FullName { get; set; }
        public int Age { get; set; }
    }
}

(2)AutoMapperProfile.cs(映射规则)的配置

【需求】Student 类的 Name 字段映射到 Teacher 类的 FullName 字段

using AutoMapper;

namespace ConsoleApp1
{
    public class AutoMapperProfile : Profile
    {
        public AutoMapperProfile()
        {
            CreateMap<Student, Teacher>()
                .ForMember(dest => dest.FullName, opt => opt.MapFrom(src => src.Name));//配置不同名的字段映射
                                //其他字段:字段名称一样的自动映射

        }
    }
}
dest(destination)是目标类的意思,opt是选择的意思,即选择Name的字段映射给FullName。

(3)使用映射(程序入口)

using AutoMapper;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 配置规则
            var configuration = new MapperConfiguration(cfg =>
            {
                cfg.AddProfile<AutoMapperProfile>();
            });

            // 创建映射器
            IMapper mapper = configuration.CreateMapper();

            // 创建学生实体
            var student = new Student
            {
                Id = 1,
                Name = "小苏",
                Age = 20
            };

            // 映射成老师
            var teacher = mapper.Map<Teacher>(student);

            Console.WriteLine($"Teacher: Id={teacher.Id}, FullName={teacher.FullName}, Age={teacher.Age}");
            //输出:Teacher: Id=1, FullName=小苏, Age=20

        }
    }
}

三、ABP框架Demo

(1)AutoMapperProfile.cs(映射规则)的配置

        配置位置如上,每个应用层都有一个这个类文件,配置内容同控制台程序,就是写个CreateMap<T,V>()

(2)ABP框架下实体映射的三种方式

方案一二(注入):

[Route("api/books")]
public class BookAppService : ApplicationService, IBookAppService
{
    private readonly IBookService _bookService;
    private readonly IObjectMapper _objectMapper;//using Volo.Abp.ObjectMapping;
    public BookAppService(
        IBookService bookService,
        IObjectMapper objectMapper
        )
    {

        _bookService = bookService;
        _objectMapper = objectMapper;
    }

    [Route("getbookbybll")]
    [HttpGet]
    public async Task<List<BookDto>> GetListByBLLAsync()
    {
        List<BookDto> list = await _bookService.GetBooks();//假设有一个服务可以获取List<BookDto>
        List<Book> test1 = ObjectMapper.Map<List<BookDto>,List<Book>>(list);//方案一,底层接口或者WebApi控制器继承ApplicationService,直接使用ObjectMapper(前提:应用层配置好映射关系CreateMap)
        List<Book> test2 = _objectMapper.Map<List<BookDto>,List<Book>>(list);//方案二,注入IObjectMapper使用(前提:应用层配置好映射关系CreateMap)
        return list;
    }

}

方案三:

var config = new MapperConfiguration(cfg => cfg.AddProfile<XXXXXXXXAutoMapperProfile>());//XXXXXXXXAutoMapperProfile 配置CreateMap规则
var list = config.CreateMapper().Map<List<源类>, List<目标类>>(list); //list是源类的列表数据

【原理】ABP 框架在启动时通过自动扫描模块中的 Profile 类(继承自 AutoMapper.Profile)并将其自动注册到 IObjectMapper 中,我们可以通过ObjectMapper使用映射。

四、常见配置

1.映射检查及双向映射

        1.CreateMap<T,V>()中,允许一个入参控制是否进行映射检查

        2.可通过ReverseMap()方法决定是否支持双向映射。

//映射规则:例如可以传入   CreateMap<源类,目标类>(MemberList.Source)
public enum MemberList
{
    Destination,//CreateMap不传参默认也是这种,【目标类有未被映射成员=>报错】
    Source,//【源类有未映射出去的成员=>报错】
    None//【源类,目标类是否被映射都不报错】
} 

         例如可以写成:

CreateMap<Book, BookDto>(MemberList.None);//不检查是否映射成功(直接实体转为Dto,能转多少是多少)
CreateMap<Book, BookDto>(MemberList.None).ReverseMap();//不检查是否映射成功+双向映射(实体可转为Dto,Dto可转为实体)

2.遍历修改

例如以下规则,就是Student(Name= "John")=>Teacher (FullName ="新名字John") 

.ForMember(dest => dest.FullName, opt => opt.MapFrom(src => "新名字" + src.Name));
.ForMember(dest => dest.FullName, opt => opt.MapFrom(src => NameHelper.GetName(src.Name)));//调用某个方法

3.多字段映射写法

CreateMap<Student, Teacher>()
                .ForMember(dest => dest.FullName, opt => opt.MapFrom(src => src.Name))
                .ForMember(略)
                .ForMember(略);

4.映射字段的忽略(含不可访问属性)

假如public string Name { get; }  (没有set方法)会报错

解决方案一(封装方法判断此情况,自动跳过):

CreateMap<Student, Teacher>()
.IgnoreAllPropertiesWithAnInaccessibleSetter()
.IgnoreAllSourcePropertiesWithAnInaccessibleSetter(); // 忽略所有设置器不可访问的属性

解决方案二(不选择字段映射到FullName):

CreateMap<Student, Teacher>()
.ForMember(dest => dest.FullName, opt => opt.Ignore()); // 明确忽略特定属性

五、常见问题

1.通用检查方法

请逐步排查:

①是否定义了CreateMap的映射(检查双向映射等)

②定义的映射类型是否准确(看第二点)

③是否调用时写错了类名、混淆了实体和列表(看第三点)

2.类型映射失败

错误信息

Error mapping types.

Mapping types:
Object -> List`1
System.Object -> System.Collections.Generic.List`1[[XXXDto, Appliction.Contracts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]

 方案:检查CreateMap的映射类型,确保一致(这个也太tm坑了,编译居然没有类型检查,我选择了string映射到decimal? , 启动居然没报错,查询触发才报错,不过改成一样类型的就可以了

3.映射语法报错

        CreateMap定义只写实体即可,不需要写List的

public class StudentProfiles : Profile
{
    public StudentProfiles() 
    {
        CreateMap<Student, StudentDto>(); //不需要配置List
    }
}

        但是映射时则要分清实体和列表。下面是调用的例子:

var list = config.CreateMapper().Map<List<源类>, List<目标类>>(list); //list是源类的列表数据
var entity= config.CreateMapper().Map<源类,目标类>(en); //en是源类的实体数据

4.为什么需要写DTO?

  • 保密性:确保数据表加字段不会返回多余的数据
  • 简洁性:按需返回字段给前端
  • 兼容性:DTO可用于数据转换和格式化
  • 灵活性:业务逻辑和数据传输分开,无论表怎么改,DTO实体都是共通的(便于迁移 换库)
“DRY——避免重复代码”是一个优秀的开发者在开发软件时所具备的最重要的思想之一。我们在开发企业WEB应用程序时都有一些类似的需求,例如:都需要登录页面、用户/角色管理、权限验证、数据有效性验证、多语言/本地化等等。一个高品质的大型软件都会运用一些最佳实践,例如分层体系结构、领域驱动设计、依赖注入等。我们也可能会采用ORM、数据库迁移(Database Migrations)、日志记录(Logging)等工具。 从零开始创建一个企业应用程序是一件繁琐的事,因为需要重复做很多常见的基础工作。许多公司都在开发自己的应用程序框架来重用于不同的项目,然后在框架的基础上开发一些新的功能。但并不是每个公司都有这样的实力。假如我们可以分享的更多,也许可以避免每个公司或每个项目的重复编写类似的代码。作者之所以把项目命名为“ASP.NET Boilerplate”,就是希望它能成为开发一般企业WEB应用的新起点,直接把ABP作为项目模板。 ABP的全称是Asp.net boilerplate project(asp.Net样板工程)。是github上非常活跃的一个开源项目。它并没有使用任何新的技术,只是由两名架构师将asp.net开发中常用的一些工具整合到了一起,并且部分实现了DDD的概念。是一个开箱即用的框架,可以作为asp.net分布式应用的一个良好起点。 它的功能包括: 服务器端: 基于最新的.NET技术 (目前是ASP.NET MVC 5、Web API 2、C# 5.0,在ASP.NET 5正式发布后会升级) 实现领域驱动设计(实体、仓储、领域服务、领域事件、应用服务、数据传输对象,工作单元等等) 实现分层体系结构(领域层,应用层,展现层和基础设施层) 提供了一个基础架构来开发可重用可配置的模块 集成一些最流行的开源框架/库,也许有些是你正在使用的。 提供了一个基础架构让我们很方便地使用依赖注入(使用Castle Windsor作为依赖注入的容器) 提供Repository仓储模式支持不同的ORM(已实现Entity Framework 、NHibernate、MangoDb和内存数据库) 支持并实现数据库迁移(EF 的 Code first) 模块化开发(每个模块有独立的EF DbContext,可单独指定数据库) 包括一个简单的和灵活的多语言/本地化系统 包括一个 EventBus来实现服务器端全局的领域事件 统一的异常处理(应用层几乎不需要处理自己写异常处理代码) 数据有效性验证(Asp.NET MVC只能做到Action方法的参数验证,ABP实现了Application层方法的参数有效性验证) 通过Application Services自动创建Web Api层(不需要写ApiController层了) 提供基类和帮助类让我们方便地实现一些常见的任务 使用“约定优于配置原则” 客户端: Bootstrap、Less、AngularJs、jQuery、Modernizr和其他JS库: jQuery.validate、jQuery.form、jQuery.blockUI、json2等 为单页面应用程序(AngularJs、Durandaljs)和多页面应用程序(Bootstrap+Jquery)提供了项目模板。 自动创建Javascript 的代理层来更方便使用Web Api 封装一些Javascript 函数,更方便地使用ajax、消息框、通知组件、忙状态的遮罩层等等 除ABP框架项目以外,还开发了名叫“Zero”的模块,实现了以下功能: 身份验证与授权管理(通过ASP.NET Identity实现的) 用户&角色管理 系统设置存取管理(系统级、租户级、用户级,作用范围自动管理) 审计日志(自动记录每一次接口的调用者和参数) 我共享的资料包含ABP(2.02版本)的一个Demo文件以及调试时候需要填的坑的处理方法(填了蛮久才填满。。。),还包括一本ABP中文教程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值