Mapster上下文在嵌套映射中为空



如何使用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 exceptionMapContext.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

相关内容

  • 没有找到相关文章

最新更新