Automapper 在映射 1400 条记录时运行速度极慢

作者:编程家 分类: 编程代码 时间:2025-08-22

Automapper 在映射 1400 条记录时运行速度极慢

Automapper 是一个用于对象到对象映射的开源库,它可以帮助开发人员简化对象之间的转换过程。然而,在某些情况下,当映射的记录数增加到一定数量时,Automapper 的性能可能会受到影响,导致映射过程变得极慢。本文将探讨这个问题,并提供一些解决方案。

案例代码

假设我们有一个 Student 类和一个 StudentDTO 类,它们具有相同的属性,但是在某些情况下需要进行转换。以下是它们的定义:

csharp

public class Student

{

public int Id { get; set; }

public string Name { get; set; }

public int Age { get; set; }

// 其他属性...

}

public class StudentDTO

{

public int Id { get; set; }

public string Name { get; set; }

public int Age { get; set; }

// 其他属性...

}

我们使用 Automapper 进行映射的代码如下所示:

csharp

var config = new MapperConfiguration(cfg => cfg.CreateMap());

var mapper = config.CreateMapper();

var students = GetStudentsFromDatabase(); // 从数据库获取学生记录

var studentDTOs = mapper.Map>(students);

上述代码中,我们首先创建了一个 MapperConfiguration 对象,并定义了 Student 到 StudentDTO 的映射关系。然后,我们使用这个配置创建了一个 IMapper 对象。最后,我们从数据库获取了学生记录,并使用 Automapper 进行映射。

Automapper 在映射 1400 条记录时的性能问题

在上述的代码中,当我们试图映射一大批记录时(比如 1400 条记录),我们可能会遇到性能问题。这是因为 Automapper 的默认行为是使用反射来获取类型的属性,并且每次映射时都会进行属性的查找和赋值操作,这在大批量映射时会导致性能下降。因此,我们需要寻找一种优化的方法来改善 Automapper 的性能。

使用 Expression 编译映射规则

为了提高 Automapper 的性能,我们可以使用 Expression 编译映射规则。Expression 是一个强大的功能,它允许我们动态地生成代码,并将其编译为可执行代码。通过使用 Expression,我们可以避免反射操作,从而提高映射的性能。

以下是使用 Expression 编译映射规则的代码示例:

csharp

var config = new MapperConfiguration(cfg =>

{

var studentMapExpression = CreateMapExpression();

cfg.CreateMap().ConvertUsing(studentMapExpression);

});

var mapper = config.CreateMapper();

var students = GetStudentsFromDatabase(); // 从数据库获取学生记录

var studentDTOs = mapper.Map>(students);

在上述代码中,我们定义了一个 CreateMapExpression 方法,用于根据 Student 类型和 StudentDTO 类型创建一个 Expression 实例。然后,我们使用 ConvertUsing 方法将这个 Expression 实例应用到映射配置中。

以下是 CreateMapExpression 方法的实现:

csharp

public static Expression> CreateMapExpression()

{

var sourceProperties = typeof(TSource).GetProperties();

var destinationProperties = typeof(TDestination).GetProperties();

var sourceParameter = Expression.Parameter(typeof(TSource), "source");

var bindings = destinationProperties

.Select(destProp =>

{

var sourceProp = sourceProperties.FirstOrDefault(srcProp => srcProp.Name == destProp.Name);

if (sourceProp != null && sourceProp.PropertyType == destProp.PropertyType)

{

return Expression.Bind(destProp, Expression.Property(sourceParameter, sourceProp));

}

return null;

})

.Where(binding => binding != null);

var memberInit = Expression.MemberInit(Expression.New(typeof(TDestination)), bindings);

return Expression.Lambda>(memberInit, sourceParameter);

}

上述 CreateMapExpression 方法首先获取源类型和目标类型的属性列表。然后,它使用这些属性创建了一个 Expression.Bind 实例,该实例将源属性和目标属性进行绑定。最后,它使用 Expression.MemberInit 将这些绑定应用到目标类型的实例上,并创建一个 Lambda 表达式。

通过使用 Expression 编译映射规则,我们可以避免反射操作,从而提高 Automapper 在大批量映射时的性能。

在本文中,我们讨论了当使用 Automapper 进行映射大批量记录时可能遇到的性能问题。我们提供了一种使用 Expression 编译映射规则的解决方案,以提高 Automapper 的性能。通过避免反射操作,我们可以显著提高 Automapper 在大批量映射时的运行速度。