Mapster 适用于 .NET 的高性能映射器

作者:微信公众号:【架构师老卢】
1-31 10:2
57

概述:MAPSTER 是用于 .NET 应用程序的高性能对象到对象映射器。它是一个库,它提供了一种将一种对象类型转换为另一种对象类型的方法,当您想要在应用程序中的层之间转换数据时,例如从数据访问层到业务逻辑层,或从业务逻辑层到表示层,这特别有用。Mapster的主要优势:Mapster的设计在速度和内存方面都很高效。我们可以在仅使用 1/3 内存的情况下获得 4 倍的性能提升。性能和内存效率高简单易用配置灵活基于属性的配置查询投影映射器工具之间的性能和内存比较 — 图片来源:这里设置和使用在 ASP.NET Core 应用程序中,您可能希望将 Mapster 配置为服务,以便可以在整个应用程序中注入

MAPSTER 是用于 .NET 应用程序的高性能对象到对象映射器。它是一个库,它提供了一种将一种对象类型转换为另一种对象类型的方法,当您想要在应用程序中的层之间转换数据时,例如从数据访问层到业务逻辑层,或从业务逻辑层到表示层,这特别有用。

Mapster的主要优势

Mapster的设计在速度和内存方面都很高效。我们可以在仅使用 1/3 内存的情况下获得 4 倍的性能提升。

  • 性能和内存效率高
  • 简单易用
  • 配置灵活
  • 基于属性的配置
  • 查询投影

映射器工具之间的性能和内存比较 — 图片来源:这里

设置和使用

在 ASP.NET Core 应用程序中,您可能希望将 Mapster 配置为服务,以便可以在整个应用程序中注入和使用它。我们现在将看到如何设置它。

使用 NuGet 包管理器控制台安装包。

Install-Package Mapster  
Install-Package Mapster.DependencyInjection

我们将使用 Mapster 创建一个复杂的映射场景,该对象包含各种属性类型,包括集合和嵌套对象。然后,我们将它映射到 .ProductProductDto

源类(产品和评论)

public class Product  
{  
    public int Id { get; set; }  
  
    public string Name { get; set; }  
  
    public DateTime ReleaseDate { get; set; }  
  
    public List<string> Tags { get; set; }  
  
    public List<Review> Reviews { get; set; }  
  
    public decimal Price { get; set; }  
}  
  
// Product will have multiple Reviews  
public class Review  
{  
    public string ReviewerName { get; set; }  
  
    public string Content { get; set; }  
}

目标类(ProductDto 和 ReviewDto)


public class ProductDto  
{  
    public int Id { get; set; }  
  
    public string Name { get; set; }  
  
    // as a formatted string   
    public string ReleaseDate { get; set; }   
  
    public List<string> Tags { get; set; }  
  
    public List<ReviewDto> Reviews { get; set; }  
  
    public decimal Price { get; set; }  
}  
  
public class ReviewDto  
{  
    public string ReviewerName { get; set; }  
  
    public string Content { get; set; }  
}

配置映射

在单独的类或方法中定义映射。这样可以使您的配置井井有条且易于管理。配置映射以处理复杂类型,包括列表和嵌套对象。

public static class MapsterConfig  
{  
    public static void Configure()  
    {  
        // Configure Product to ProductDto mapping  
        TypeAdapterConfig<Product, ProductDto>.NewConfig()  
  
            .Map(dest => dest.Id, src => src.Id)  
  
            .Map(dest => dest.Name, src => src.Name)  
  
            .Map(dest => dest.ReleaseDate, src => src.ReleaseDate.ToString("yyyy-MM-dd"))  
  
            // direct list mapping  
            .Map(dest => dest.Tags, src => src.Tags)   
  
            // nested objects mapping  
            .Map(dest => dest.Reviews, src => src.Reviews.Adapt\<List\<ReviewDto>>())   
  
            .Map(dest => dest.Price, src => src.Price);  
          
        // Configure Review to ReviewDto mapping  
        TypeAdapterConfig<Review, ReviewDto>.NewConfig()  
  
            .Map(dest => dest.ReviewerName, src => src.ReviewerName)  
  
            .Map(dest => dest.Content, src => src.Content);  
  
        // Any other mappings  
    }  
}

将 Mapster 注册到 Service Collection

在您的或程序注册文件(取决于您使用的 .NET 版本)中,将 Mapster 和映射配置注册到服务集合。Startup.cs

public class Startup  
{  
    public void ConfigureServices(IServiceCollection services)  
    {  
        // Add framework services.  
        services.AddControllers();  
          
        // Register Mapster  
        services.AddMapster();  
  
        // Configure Mapster  
        MapsterConfig.Configure();  
    }  
  
    // Configure method...  
}

注射和使用

您可以将 Mapster 提供的接口注入到您的控制器或服务中,并使用它来执行映射。在此设置中,Mapster 与 .NET 依赖项注入系统集成,提供了一种干净且可维护的方式来管理对象到对象的映射。IMapper


public class ProductsController : ControllerBase  
{  
    private readonly IMapper _mapper;  
  
    // assuming you have a repository that has GetProductAsync method.  
    private readonly IProductRepository _repository;  
  
    public ProductsController(IMapper mapper, IProductRepository productRepository)  
    {  
        _mapper = mapper;  
  
        _repository = productRepository;  
    }  
  
    [HttpGet("{id}")]  
    public async Task<IActionResult> GetProduct(int id)  
    {  
        var product = await _repository.GetProductAsync(id);  
  
        var productDto = _mapper.Map<ProductDto>(product);  
  
        return Ok(productDto);  
    }  
}

或者使用没有依赖注入的 Mapster

var product = new Product  
{  
    // ... initialize with data ...  
};  
  
var productDto = product.Adapt<ProductDto>();

不使用 MapperMock 对映射进行单元测试

[TestClass]  
public class ProductsControllerTests  
{  
    private IMapper _mapper;  
  
    private Mock<IProductRepository> _mockRepository;  
  
    private ProductsController _controller;  
  
    [TestInitialize]  
    public void Initialize()  
    {  
        // Initialize and configure Mapster mapper  
        var config = new TypeAdapterConfig();  
  
        MapsterConfig.Configure(config);  
  
        _mapper = new Mapper(config);  
  
        _mockRepository = new Mock<IProductRepository>();  
  
        _controller = new ProductsController(_mapper, _mockRepository.Object);  
    }  
}

在此设置中,是对映射配置方法的调用,以确保映射器的配置与应用程序中的设置方式一致。MapsterConfig.Configure(config)

[TestMethod]  
public async Task GetProduct_ReturnsProductDto()  
{  
    // Arrange  
    var productId = 1;  
    var product = new Product {   
      Id = productId,   
      Name = "Mapster"  
      /* other properties */   
    };  
  
    _mockRepository.Setup(repo => repo.GetProductAsync(productId))  
        .ReturnsAsync(product);  
  
    // Act  
    var result = await _controller.GetProduct(productId);  
  
    // Assert  
    var okResult = result as OkObjectResult;  
  
    Assert.IsNotNull(okResult);  
  
    Assert.AreEqual(StatusCodes.Status200OK, okResult.StatusCode);  
  
    var resultProductDto = okResult.Value as ProductDto;  
  
    Assert.IsNotNull(resultProductDto);  
  
    // You can add more assertions based on your properties  
    Assert.AreEqual(product.Id, resultProductDto.Id);   
  
    //assert other properties  
}  
 

通过使用实际的映射器,您的测试将涵盖映射配置,从而提供更集成的测试场景,确保控制器逻辑和映射配置都按预期工作。

Mapster 与 AutoMapper:比较表

Mapster 和 AutoMapper 都是用于对象到对象映射的优秀库。它们之间的选择通常归结为特定的项目需求、性能考虑以及个人或团队偏好。

Mapster 通常因其性能和简单性而受到称赞,尤其是在更复杂的映射场景中,而 AutoMapper 以其成熟度和广泛的社区支持而闻名。

阅读排行