1

I am playing around with valueinjecter and wondering how do I do viewmodels to domains when the view model has a collection of viewmodels?

Say I have this domain

   public class MyDomain
   {
       public IList<MyOtherDomain> MyOtherDomains {get; set;}
   }

   public class MyOtherDomain
   {
       public string Name {get; set;}
   }

   public class MyMasterVM
   {
       public IList<MyOtherVm> MyOtherDomains {get; set;}
   }    

   public class MyOtherVm
   {
       public string Name {get; set;}
   }

now how do I do my injecting? Do I need to manually map these with valueinjector?

public ActionResult Method(MyMasterVM vm)
{
   MyDomain d = new MyDomain();
    d.InjectFrom<UnflatLoopValueInjection>(vm);
}

Edit

After some playing around I got the simulator to work. However mine is different than the one in the tests

// sample test
   public class FooBar : TypeMapper<Foo, Bar>
        {
            public override Bar Map(Foo source, Bar target)
            {
                base.Map(source, target);
                target.NoConvention = source.Name + source.Xyz + source.Props;
                return target;
            }
        }

             [Test]
    public void MapShouldMapCollectionPropertiesAndUseFooBarTypeMapper()
    {
        MapperFactory.AddMapper(new FooBar());
        var foo = new Foo
        {
            Foos = new List<Foo>
                       {
                           new Foo{Name = "f1",Props = "v",Xyz = 19},
                           new Foo{Name = "f2",Props = "i",Xyz = 7},
                           new Foo{Name = "f3",Props = "v",Xyz = 3},
                       }
        };

        var bar = Mapper.Map<Foo, Bar>(foo);

        Assert.AreEqual(foo.Foos.Count(), bar.Foos.Count());

        var ffoos = foo.Foos.ToArray();
        var bfoos = bar.Foos.ToArray();

        for (var i = 0; i < ffoos.Count(); i++)
        {
            Assert.AreEqual(ffoos[i].Name, bfoos[i].Name);
            Assert.AreEqual(ffoos[i].Name + ffoos[i].Xyz + ffoos[i].Props, bfoos[i].NoConvention);
        }
    }

        // mine
public class Test : TypeMapper<IList<MyOtherVm>, IList<MyOtherDomain>> 
    {
        public override IList<MyOtherDomain> Map(IList<MyOtherVm> source, IList<MyOtherDomain> target)
        {
            // not sure if I always have to call base
            // mapping would happen here.
            return base.Map(source, target);
        }
    }

       MapperFactory.AddMapper(new Test());
            IList<MyOtherDomain> otherDomains= new List<MyOtherDomain>();
           MapperVj.Map(vm.MyOtherDomains , otherDomains);

I have to specify it is a IList otherwise it never seems to go into my overridden method.

chobo2
  • 83,322
  • 195
  • 530
  • 832
  • Is the type of MyDomain.MyOtherDomains correct? Should it be `IList` – David Fox Dec 20 '11 at 19:26
  • @chobo2 You didn't had to create your Test :TypeMapper, just do Mapper.Map – Omu Dec 24 '11 at 10:58
  • new TypeMapper is needed only when you have a mapping that doesn't fit into any convention (hence the test class Property Name "NoConvention") – Omu Dec 24 '11 at 11:05
  • I did a new test project that you can download, it uses your classes also, get it here: http://valueinjecter.codeplex.com/releases/view/60311#DownloadId=318259 – Omu Dec 24 '11 at 11:19

2 Answers2

1

I think you'd need to implement your own custom IValueInjection injector. I am also basing this answer on a typo in your MyDomain class.

Assumption of typo:

MyDomain.MyOtherDomains : IList<MyOtherDomains>

and not

MyDomain.MyOtherDomains : IList<MyOtherVm>

So, the customer injection class could look like this (not 100% if there's a better way to do it)

public class CustomInjecter : IValueInjection
{
    public object Map(object source, object target)
    {
        MyDomain result = new MyDomain();
        result.MyOtherDomains = new List<MyOtherDomain>();

        foreach (MyOtherVm vm in (source as MyMasterVM).MyOtherVMs)
        {
            MyOtherDomain od = new MyOtherDomain();
            // inject commonly named properties of each "child" VM
            od.InjectFrom(vm);
            result.MyOtherDomains.Add(od);
        }

        return result;
    }
}

In your controller, you can use it almost like you specified above (just change the injector type)

public ActionResult Method(MyMasterVM vm)
{
    MyDomain d = new MyDomain();
    d.InjectFrom<CustomInjecter>(vm);
    // ...
}
David Fox
  • 10,603
  • 9
  • 50
  • 80
  • Typo corrected....So is this just because it is in a collection? I have a property Called IssuerName that would be Issuer.Name and it has no problem doing those ones. – chobo2 Dec 20 '11 at 23:12
  • @chobo2 I'm not *certain* this has to be done because it's a collection. It's just the basic way of writing your own custom `ValueInjection`. There may be some more elegant way that I don't see in the documentation. – David Fox Dec 23 '11 at 23:07
1

one quick and easy way would be to do this:

MyDomain.MyOtherDomains =
vm.MyOtherDomains.Select(o => new MyOtherDomain().InjectFrom(o))
.Cast<MyOtherDomain>();

edit: I did a new test project that you can download (it uses your classes also). get it here: http://valueinjecter.codeplex.com/releases/view/60311#DownloadId=318259

Omu
  • 69,856
  • 92
  • 277
  • 407
  • I will try that. Is this just because I have a collection of these? – chobo2 Dec 22 '11 at 18:56
  • @chobo2 it's 2 properties of 2 different types, IEnumerable and IEnumerable, the default InjectFrom() will not affect them, so you either to do it manually or use an injection that does something, there's a more generic one for collection in the "Automapper simulation" on codeplex site, EnumerabelTypeMapper which will involve using a custom Mapper class, you can look at the unit tests at the bottom and see how it works http://valueinjecter.codeplex.com/wikipage?title=Automapper%20Simulation&referringTitle=Home – Omu Dec 22 '11 at 21:35
  • Your code seems not to work since MyDomain.MyOtherDomains is a IList collection and your select returns IEnumerable. I tried to do ToList but still does not work. – chobo2 Dec 23 '11 at 05:43
  • Do you recommend then to use the automapper simulation then? – chobo2 Dec 23 '11 at 05:44
  • I tried the simulator but it I got a error. Let me grab it when I can. I will also try your cast thing. – chobo2 Dec 23 '11 at 19:41
  • Ok that does not cause it to crash but it does not bind anything. So not sure how to debug it and figure out why it does not bind. I made sure the names are the same. – chobo2 Dec 23 '11 at 21:59
  • Maybe I am not using the automapper simulator right. I don't get this //FooBar is a class that implements ITypeMapper ( inherit the base class TypeMapper and add additional mapping code). Do I have to have a method or something that does the mapping manually? Do I have to override the Map method? – chobo2 Dec 23 '11 at 22:08