AutoMapper与ValueInjecter [关闭]


209

每当我在StackOverflow上寻找AutoMapper内容时,我都会在阅读有关ValueInjecter的内容

有人可以告诉我它们之间的优缺点(性能,功能,API使用率,可扩展性,测试)吗?


2
我看到很多提到的另一个是EmitMapper
adrianbanks 2011年

1
那胶水呢 gum.codeplex.com看起来也很不错,但是我还没有尝试过。我会在下个月。我也看过一个名为EmitMapper的项目emitmapper.codeplex.com
Trygve

看到一篇文章谈到这两个工具- devproconnections.com/development/...
乔治Birbilis

Answers:


170

作为ValueInjecter的创建者,我可以告诉你我这样做是因为我想要简单而又非常灵活的东西

我真的不喜欢写太多或写很多monkey code类似的东西:

Prop1.Ignore, Prop2.Ignore etc.
CreateMap<Foo,Bar>(); CreateMap<Tomato, Potato>(); etc.

ValueInjecter 类似于mozilla,带有其插件,您可以创建ValueInjections并使用它们

有内置的用于扁平化,非扁平化的注入,还有一些旨在继承

并且它以方面类型的方式工作得更多,您不必指定所有属性为1对1,而是可以执行以下操作:

从源中获取所有以“ Id”结尾的int属性,转换值并将每个属性设置为源对象中具有相同名称的一个属性,其名称不带Id后缀,并且其类型是从Entity继承的,诸如此类

所以一个明显的区别是,ValueInjecter即使在具有展平和展平的Windows窗体中也可以使用,这就是它的灵活性

(从对象映射到窗体控件,然后再返回)

Automapper,不能在Windows窗体中使用,没有展开,但是它具有诸如集合映射之类的好东西,因此,如果需要ValueInjecter使用它,您可以执行以下操作:

foos.Select(o => new Bar().InjectFrom(o));

您还可以使用ValueInjecter来映射匿名动态对象

差异:

  • 自动映射器为每种映射可能性创建配置CreateMap()

  • 从任何对象到任何对象的valueinjecter注入(在某些情况下,从对象到valuetype的注入)

  • automapper已构建了flattening,仅适用于简单类型或相同类型,并且没有unflattening

  • valueinjecter只有当你需要它,你做的target.InjectFrom<FlatLoopValueInjection>(source); also <UnflatLoopValueInjection> ,如果你想从Foo.Bar.Name of type StringFooBarName of type Class1你继承FlatLoopValueInjection并指定此

  • 默认情况下,automapper映射具有相同名称的属性,对于其余属性,您必须一一指定,并执行诸如Prop1.Ignore(),Prop2.Ignore()等操作。

  • valueinjecter具有默认的注入.InjectFrom(),其名称和类型相同;除此以外,您还可以使用单独的映射逻辑/规则创建自定义值注入,更像是方面,例如从Foo类型的所有道具到Bar类型的所有道具


5
对于爱神,请告诉我ValueInjector可以使用深图ViewModel并映射到深图业务实体/从深图业务实体映射,并且无需做任何工作就可以映射完全相同的所有内容,并且我只需要指定如何处理不同之处即可。我一直希望AutoMapper能够添加此功能,但是它从未实现过,而且我还没有时间编写自己的自动映射器。
克里斯·马里西奇

3
@Chris Marisic,您可以使用它进行操作,以防万一,您需要进行深度克隆,一旦递归地执行了此操作,但我不适用于集合属性valueinjecter.codeplex.com/Thread/View.aspx?ThreadId=236126,或者您可以执行Flat ViewModel并使用展平和展平,这很容易
Omu

ViewModel和Domain Entities将相似但不同,因此不是纯克隆。90%的属性通常是确切的类型和名称,ViewModels常常以SelectLists和绑定到它们的东西结尾,而我想忽略它们回到域。两者都很有可能在它们上面有对象的集合。
克里斯·马里西奇

27
<pedant>看起来很酷,但也许应该是ValueInjectOr?</pedant>
Craig Stuntz 2011年

1
但由于某种原因,它是错误的:)
Omu

59

由于我从未使用过任何其他工具,因此我只能谈论AutoMapper。我在构建AutoMapper时有一些目标:

  • 支持展平以使DTO对象变得愚蠢
  • 开箱即用地支持明显的场景(集合,枚举等)
  • 能够轻松验证测试中的映射
  • 允许使用极端情况来解析其他位置的值(自定义类型->类型映射,单个成员映射以及一些非常疯狂的极端情况)。

如果您想做这些事情,AutoMapper会非常适合您。AutoMapper不好的事情是:

  • 填充现有对象
  • 展平

原因是我从来不需要做这些事情。在大多数情况下,我们的实体没有设置器,没有公开集合等,因此这就是为什么它不存在的原因。我们使用AutoMapper展平到DTO并从UI模型映射到命令消息等。那对我们真的非常有效。


1
@Jimmy Bogard您是否看到填充现有对象会使其进入AutoMapper的功能列表?
罗马,

我还没有尝试过ValueInjecter,但是对于我们需要的东西,自动映射器非常强大。
richb01 2012年

我认为这里最重要的是可验证性。重命名和重构事物时,这是一个巨大的帮助。
Kugel 2014年

55

我尝试了两者,并且更喜欢ValueInjecter,因为它是如此简单:

myObject.InjectFrom(otherObject);

我绝大多数的注射需求都知道这些。它不可能比这更简单和优雅。


1
this object扩展方法在那里?
克里斯·马里西奇

2
如何将代码与ValueInjecter分离?对我来说,似乎总是对ValueInjecter有所依赖,即在我的Web项目中,因为我直接在给定对象上使用ValueInjecter(扩展方法)。
Rookian 2011年

1
@Rookian老实说,这不是您应该过多考虑的问题。您可以依靠提到的@Omu这样的接口,因此,如果您更改映射器,则可以节省一些工作(可能不多)。除非您想进入全面的AOP,否则这种类型的依赖关系很难抽象出来,不幸的是,由于.NET不能正确地提供AOP支持,因此很多时候这种依赖是不可撤消的。现在,您可以AOP删除一些映射,尤其是如果您使用MVC并编写处理ViewModel / DomainModel映射的动作过滤器。
克里斯·马里西奇

13
为什么包装器是最佳解决方案?如果要切换映射器,唯一要做的就是自己实现InjectFrom()扩展方法。
jgauffin

1
我也尝试过,而且我更喜欢AutoMapper。我将其用于系统的一小部分,在其中我将实体与Linq2Sql生成的类进行映射。默认情况下,简单映射为StockTotalQuantity-> stock_size_quantity或UserId-> user_id确实适用于AutoMapper。即使添加了对流后,它也无法与ValeInjecter一起使用。现在坚持使用AutoMapper。
ArturKędzior2012年

27

这也是我一直在研究的一个问题,就我的用例而言,这似乎是价值注入者的不二之选。它不需要事先设置即可使用(我猜可能会影响性能,尽管如果实施得当,它可以缓存映射以供将来调用,而不是每次都反映出来),因此您无需在使用它们之前预先定义任何映射。

但是最重​​要的是,它允许反向映射。现在我可能在这里丢失了一些东西,因为Jimmy提到他认为没有必要的用例,所以也许我的模式是错误的,但是我的用例是我正在从ORM创建一个ViewModel对象。然后,我将其显示在我的网页上。用户完成操作后,将ViewModel作为httppost重新获得,如何将其转换回原始的ORM类?我很想知道与自动映射器的模式。使用ValueInjector时,它是微不足道的,甚至不会变平。例如创建一个新实体

由entityframework创建的模型(首先是模型):

public partial class Family
{ 
    public int Id { get; set; }
    public string FamilyName { get; set; }

    public virtual Address Address { get; set; }
}

public partial class Address
{
    public int Id { get; set; }
    public string Line1 { get; set; }
    public string Line2 { get; set; }
    public string TownCity { get; set; }
    public string County { get; set; }
    public string Postcode { get; set; }

    public virtual Family Family { get; set; }
}

ViewModel(可以使用验证器进行装饰):

public class FamilyViewModel
{
    public int Id { get; set; }
    public string FamilyName { get; set; }

    public int AddressId { get; set; }
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string AddressTownCity { get; set; }
    public string AddressCounty { get; set; }
    public string AddressPostcode { get; set; }
}

ViewController:

    //
    // GET: /Family/Create

    public ActionResult Create()
    {
        return View();
    } 

    //
    // POST: /Family/Create

    [HttpPost]
    public ActionResult Create(FamilyViewModel familyViewModel)
    {
        try
        {
            Family family = new Family();
            family.InjectFrom<UnflatLoopValueInjection>(familyViewModel);
            db.Families.Add(family);
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }

在我看来,没有比这更简单的了吗?

(所以这引出了一个问题,我碰到的模式有什么问题(似乎很多人都这样做了),它对AutoMapper来说没有价值吗?)

但是,如果要确定的是您要使用的这种模式,那么我的投票是按国家英里来衡量的。


1
可能您也应该在一个单独的问题中问这个问题,该问题标有asp.net-mvc和最佳实践,ViewModel ...,atm只要适合您,我就不会发现任何问题,但是我敢肯定有人可能有不同的意见
Omu

学会了更多的mvc。我现在可以回答我的问题。当您获得一个填充的视图模型时,更新原始模型的方法是使用mvc提供的UpdateModel()函数。
DanH 2011年

1
UpdateModel()用于填充表示视图的模型,与执行Action(MyModelClasss模型)相同
Omu

的确如此,但是如果您想要一个独立的视图模型(例如存储库模型),则可以使用它来填充假设映射是微不足道的(并且通常是这样)。当然,如果更复杂的ValueInjector成为自己的话。
2011年

1
我认为可以提出这样的论点,即您不应该简单地将属性重新设置在域模型上-您应该使用为其添加含义的方法。
Mike Cole
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.