我们在使用Automapper
的时候经常会遇到这样的问题:假设展示给用户的数据我们用UserDto
类,User
类就是我们的实体类。在给用户编辑的时候,我们可能某些字段在数据库中为Null
,这时候需要一些默认值 比如这里UserDto
中的BirTime
,然后我们有一些人的习惯是在构造函数里面进行赋值
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime? BirTime{ get; set; }
}
public class UserDto
{
public UserDto()
{
this.BirTime=DateTime.Now;//把当前时间赋值给BirTime
}
public string Name { get; set; }
public DateTime? BirTime{ get; set; }
}
//假设我们从数据库中取出来的值是这样的,然后我们要和UserDto之间进行转换
User user = new User()
{
Id = 1,
Name = "caoyc",
BirTime=null
};
UserDto userDto=user.MapTo<UserDto>();//这里把实体类转换成前台给用户展示的UserDto类
看似这里的代码都没有什么问题,但是我想在BirTime
为null
值的时候使用我UserDto
类中的默认值 也就是当前时间,但在实际操作之后就会发现转换过后的UserDto
的值已经变掉了。那么问题来了, 如何才能使用默认值呢。
方法有很多,比如
//第一种方法
UserDto userDto=user.MapTo<UserDto>();//这里把实体类转换成前台给用户展示的UserDto类
userDto.BirTime=userDto.BirTime==null?DateTime.Now:userDto.BirTime;
第一种方法就是在自己转换完成之后判断一下,然后重新赋值,用这种方法的话那写构造函数自然就没什么必要了
//第二种方法
Mapper.CreateMap<User, UserDto>().ForAllMembers(opt => opt.Condition(srs => !srs.IsSourceValueNull));
第二种方法不怎么好,当你需要转换的类很多的时候,每个都要这样写,会很多也会很烦
//第三种方法,在全局配置的时候加上这句话
private static void CreateMappingsInternal(IMapperConfigurationExpression cfg)
{
//没错就是这句话
cfg.ForAllMaps((a, b) => b.ForAllMembers(opt => opt.Condition((src, dest, sourceMember) => sourceMember != null)));
}
个人比较推荐第三种方法,不过这就相当于一棒子打死了,有利也有弊。
.NET Web API的Global.asax.cs
using Application.Dtos;
using Autofac;
using Autofac.Integration.WebApi;
using AutoMapper;
using AutoMapper.Configuration;
using Repositories.Cliente;
using System;
using System.Linq;
using System.Reflection;
using System.Web.Http;
namespace WebApi
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
var builder = new ContainerBuilder();
var config = GlobalConfiguration.Configuration;
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder
.RegisterAssemblyTypes(typeof(ClienteRepository).Assembly)
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces().InstancePerRequest();
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
var mapper = new MapperConfigurationExpression();
CreateMappingsInternal(mapper);
Mapper.Initialize(mapper);
}
//全局配置
private static void CreateMappingsInternal(IMapperConfigurationExpression mapper)
{
}
}
}
.NET Core的Startup.cs的ConfigureServices方法
public void ConfigureServices(IServiceCollection services)
{
services
.AddControllers()
.AddNewtonsoftJson();
services.AddMvc();
//...............
services.AddAutoMapper(typeof(AccountProfile));
var configuration = new MapperConfiguration(cfg =>
{
cfg.ForAllMaps((obj, cnfg) =>
cnfg.ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null)));
});
}
AutoMapper条件映射实战
//有条件的对象拷贝
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.CreateMap<OrderInfo, OrderInfo>()
.ForAllMembers(opts => opts.Condition((src, dest, srcMember, dMember) =>
srcMember != null && srcMember.ToString() != ""));
});
AutoMapper.Mapper.Map<OrderInfo, OrderInfo>(mainOrder, myorderinfo);
AutoMapper.Map
忽略来自源对象中的所有空值的属性
using AutoMapper;
using NUnit.Framework;
namespace Tests.UI
{
[TestFixture]
class AutomapperTests
{
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int? Foo { get; set; }
}
[Test]
public void TestNullIgnore()
{
Mapper.CreateMap<Person, Person>()
.ForAllMembers(opt => opt.Condition(srs => !srs.IsSourceValueNull));
var sourcePerson = new Person
{
FirstName = "Bill",
LastName = "Gates",
Foo = null
};
var destinationPerson = new Person
{
FirstName = "",
LastName = "",
Foo = 1
};
Mapper.Map(sourcePerson, destinationPerson);
Assert.That(destinationPerson,Is.Not.Null);
Assert.That(destinationPerson.Foo,Is.EqualTo(1));
}
}