209

每次我在 StackOverflow 上寻找AutoMapper的东西时,我都会读一些关于ValueInjecter的东西。

谁能告诉我它们之间的优缺点(性能、特性、API 使用、可扩展性、测试)?

4

4 回答 4

170

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

我真的不喜欢写太多或写很多monkey code像:

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

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

有用于扁平化、非扁平化和一些旨在被继承的内置注入

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

从源中获取名称以“Id”结尾的所有 int 属性,转换值并将每个属性设置为源对象中具有相同名称但没有 Id 后缀的属性,并且它的类型是从实体继承的,类似的东西

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

(从对象映射到表单控件并返回)

Automapper,不能在 Windows 窗体中使用,没有展开,但它有像集合映射这样的好东西,所以如果你需要它使用 ValueInjecter,你只需执行以下操作:

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

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

区别:

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

  • valueinjecter 从任何对象注入到任何对象(也有从对象注入到 valuetype 的情况)

  • automapper 已扁平化构建它,仅适用于简单类型或相同类型,并且它没有 unflattening

  • valueinjecter 仅在您需要时才这样做target.InjectFrom<FlatLoopValueInjection>(source); also <UnflatLoopValueInjection> ,并且如果您想要Foo.Bar.Name of type String继承FooBarName of type Class1FlatLoopValueInjection 并指定它

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

  • valueinjecter has a default injection .InjectFrom() that does the properties with the same name and type; for everything else you create your custom valueinjections with individual mapping logic/rules, more like aspects, e.g. from all props of Type Foo to all props of type Bar

于 2011-01-12T20:38:07.270 回答
59

Since I've never used any of the other tools, I can only talk about AutoMapper. I had a few goals in mind for building AutoMapper:

  • Support flattening to dumb DTO objects
  • Support obvious scenarios out of the box (collections, enumerations etc.)
  • Be able to easily verify mappings in a test
  • Allow for edge cases for resolving values from other places (custom type->type mapping, individual member mapping, and some really crazy edge cases).

If you want to do these things, AutoMapper works very well for you. Things AutoMapper doesn't do well are:

  • Filling existing objects
  • Unflattening

The reason being I've never needed to do these things. For the most part, our entities don't have setters, don't expose collections, etc. so that's why it's not there. We use AutoMapper to flatten to DTOs and map from UI models to command messages and the like. That's where it works really, really well for us.

于 2011-03-30T02:10:02.577 回答
55

I tried both and prefer ValueInjecter because it's so simple:

myObject.InjectFrom(otherObject);

That's all there is to know for the vast majority of my injection needs. It can't possibly get more simple and elegant than this.

于 2011-01-12T21:07:03.717 回答
27

This is a question I've been researching too, and for my use case, it seems to be valueinjecter hands down. It requires no prior setup to use (may hit performance I guess, although if smartly implemented it could cache the mappings for future invocations rather than reflecting each time), so you don't need to predefine any mappings before using them.

Most importantly however, it allows reverse mapping. Now I may be missing something here as Jimmy mentions that he sees no use case where its necessary, so maybe I have the pattern wrong, but my use case is that I'm creating a ViewModel object from my ORM. I then display this on my webpage. Once the user finishes I get the ViewModel back in as a httppost, how does this get converted back to the original ORM classes? I'd love to know the pattern with automapper. With ValueInjector it is trivial, and it will even unflatten. e.g Creating a new entity

The model created by the entityframework (model first):

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; }
}

The ViewModel (which I can decorate with validators):

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; }
}

The 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();
        }
    }

To my mind, it doesn't get much simpler than that?

(So this begs the question, whats wrong with the pattern that I run into this (and it seems many others do to), that its not seen as of value to AutoMapper?)

However, if this pattern as decscribed, is one you want to use, then my vote is valueinjecter by a country mile.

于 2011-04-15T03:31:24.473 回答