如何使用MapContext。当前的嵌套映射?例如:
public class Foo {
public string Name { get; set; }
}
public class Bar {
public string Name { get; set; }
}
public class Src {
public IEnumerable<Foo> Foos { get; set; }
}
public class Dst {
public IEnumerable<Bar> Bars { get; set; }
public string Name { get; set; }
}
TypeAdapterConfig<Foo, Bar>
.NewConfig()
.Map(d => d.Name, s => (string)MapContext.Current.Parameters["prefix"] + s.Name);
TypeAdapterConfig<Src, Dst>
.NewConfig()
.Map(d => d.Bars, s => s.Foos)
.Map(d => d.Name, s => (string)MapContext.Current.Parameters["prefix"]);
var src = new Src
{
Foos = new [] { "test" }
};
var dst = src
.BuildAdapter()
.AddParameter("prefix", "!")
.AdaptToType<Dst>();
当我尝试将src映射到dst时,我在尝试将foo映射到bar时得到Null reference exception
为MapContext.Current
。上下文适用于顶级映射(Dst。名称将被设置),但在嵌套映射上不可访问。怎么解呢?
如果我显式地添加调用来创建MapScopeContext
,它对我有效:
using var contextScope = new MapContextScope();
无论如何,ServiceMapper
实现应该已经在源代码中添加了它。此外,它曾经为我工作,但在一个新的XUnit测试项目中,我得到了异常:
System.InvalidOperationException: Mapping must be called using ServiceAdapter
at Mapster.TypeAdapterExtensions.GetService[TService](MapContext context)
和调试我发现MapContext.Current
属性是null
。
我想知道为什么我得到这种不一致的行为。
当使用item.Adapt<OtherClass>(mapper.Config)
时,我得到如上所述的异常,但是当使用mapper.Map<OtherClass>(item)
时,它在映射配置中与MapContext.Current.GetService<SomeService>()
一起工作得很好。
假设你使用DI,TypeAdapterConfig
的实例被注册为Singleton,ServiceMapper
(不是Mapper
,因为ServiceMapper
在调用Map<T>
时创建了一个新的上下文,而Mapper没有这样做)通过IMapper
注册为作用域服务。当使用Map<T>
代替Adapt<T>
时,内部Mapster确保MapContext
不为空
像这样输入DI:
var typeAdapterConfig = new TypeAdapterConfig();
typeAdapterConfig.Scan(...);
typeAdapterConfig.Compile();
services
.AddSingleton(typeAdapterConfig)
.AddScoped<IMapper, ServiceMapper>();
映射:
public class IdMappingConfiguration : IRegister
{
public void Register(TypeAdapterConfig config)
{
_ = config ?? throw new ArgumentNullException(nameof(config));
_ = config
.NewConfig<PocoId, DtoId>()
.Map(dest => dest.Id, src => MapContext.Current.GetService<SomeService>().Do(src.Id));
}
}
解决:和
_mapper.Map<DtoId>(idPoco);
内部映射器是这样工作的MapsterMapper.ServiceMapper
确保上下文存在:
public override TDestination Map<TDestination>(object source)
{
using var scope = new MapContextScope();
scope.Context.Parameters[DI_KEY] = _serviceProvider;
return base.Map<TDestination>(source);
}
如果您想使用DTO更新POCO:
var poco = await this._dataContext.SomeEntities.FirstAsync();
_mapper.From(dto).AdaptTo(poco);
await _dataContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
在GitHub上添加此开放问题以供参考https://github.com/MapsterMapper/Mapster/issues/230