如何将值传递给自定义的ValueResolver?

3

我在传递自定义值解析器的值格式方面遇到了困难。我基本上试图根据我的 ViewModel 将 Int 转换为对象。然而,我无法将这个值传递给我的值解析器。

我有以下自定义值解析器:

public class CustomResolver : ValueResolver<CreateContainerViewModel, Container>
{ 
    private int id = 0;

    public CustomResolver(int? sourceId)
    {
        if(sourceId.HasValue)
            id = sourceId.Value;
    }
    protected override Container ResolveCore(CreateContainerViewModel source)
    {
        if (id == 0) return null;
        else
        {
            ISession _session = DependencyResolver.Current.GetService<ISessionFactory>().GetCurrentSession();
            return _session.Get<Container>(id);
        }
    }
}

当我使用硬编码的int创建地图时,它可以正常工作,例如以下代码:

Mapper.CreateMap<CreateContainerViewModel, Container>()
.ForMember(a => a.CurrentContainer, opt => opt.ResolveUsing(src => new CustomResolver(33)));

但是当我尝试从我的视图模型中获取值时,它无法正常工作(抛出映射异常)

Mapper.CreateMap<CreateContainerViewModel, Container>()
            .ForMember(dest => dest.CurrentContainer, opt => opt.MapFrom(src => new CustomResolver(src.CurrentContainerId)));

请问有人能指引我正确的语法,以便将值传递给自定义ValueResolver吗?

谢谢。

更新:

基本上是在尝试编写类似于以下内容的代码:

  public class IdToObjectResolver<T> : ValueResolver<int, T> where T : class
{ 
    private ISession _session;
    private int id;
    public IdToObjectResolver(Nullable<int> sourceId)
    {
        _session = DependencyResolver.Current.GetService<ISessionFactory>().GetCurrentSession();
        if(sourceId.HasValue)
            id = sourceId.Value;
    }

    protected override T ResolveCore(int source)
    {
        return _session.Get<T>(source);
    }
}

这段代码目前还没有意义,只是尝试一种传递int类型的方法...


这个页面http://automapper.codeplex.com/wikipage?title=Custom%20Value%20Resolvers上说:自定义提供给解析器的源值-即将推出 :) - TomL
1个回答

2
如果我理解得正确,我认为您可能在稍微复杂化ValueResolver。如您所见,在ValueResolver的ResolveCore方法中发送了整个CreateContainerViewModel类。这将是具有值的整个源对象。
因此,您应该能够通过使用此映射从源对象中提取id值:opt.ResolveUsing(src => new CustomResolver())(不带构造函数参数)。
希望这可以帮助您。
编辑:
我的测试:
        [TestMethod]
        public void TestMethod1()
        {
            Mapper.CreateMap<CreateContainerViewModel, Container>()
                .ForMember(a => a.CurrentContainer, opt => opt.ResolveUsing<CustomResolver>());


            var source = new CreateContainerViewModel()
            {
                ID = 3
            };

            var destination = new Container();

            Mapper.Map(source, destination);

            Assert.AreEqual(destination.CurrentContainer.ID, 3);

        }

自定义解析器:

public class CustomResolver : ValueResolver<CreateContainerViewModel, Container>
{
    protected override Container ResolveCore(CreateContainerViewModel source)
    {

            return new Container() { ID = source.ID };  
    }
}

感谢@dtryon。我实际上正在尝试开发一种更通用的解决方案,以将外键ID字段解析为域中的对象。虽然发布的解决方案可以工作,但我必须为每个外键对象创建新的自定义解析器-我希望能够开发一种通用解决方案,允许我传递要映射对象的属性中的ID。 - TomL
明白了。我不确定Jimmy所说的即将到来的是什么...我认为他指的是一种更细粒度、更流畅的方式来编写ValueResolver(这样你就不必再写另一个类)。你可能正在尝试让一个映射工具去完成存储库的工作。这可能是可行的,但你正在违背AutoMapper的设计初衷(绑定两个已知类型之间的映射)。 - Davin Tryon
是的,我也觉得可能是这种情况。目前我正在使用 AutoMapper 加上一些额外的逻辑来在“映射”方法中返回外键对象。这是因为我正在使用 MVC 视图模型,在 POST 中返回这些视图模型,然后需要更新或合并现有数据库。 - TomL
通常,在您所描述的设计中,您会有视图模型和模型对象,它们大部分具有相同的属性。您将使视图模型与模型进行验证,然后从模型对象更新。在您的情况下,这种方法不起作用吗? - Davin Tryon
这正是我现在正在做的事情...但我的视图模型具有外键ID属性(即 ViewModelObject.UserId),而我的领域具有对象(即 DomainObject.User),所以我目前正在自动映射这两者,然后执行以下操作:DomainObject.User = session.Load<User>(ViewModelObject.UserId);- 我只是想知道是否有一种方法可以消除额外的步骤。(可能不值得努力 :))...无论如何感谢您的帮助,我非常感激。 - TomL
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接