How to control depth of unflattening

Jul 24, 2013 at 2:33 PM
Edited Jul 24, 2013 at 2:34 PM
Hi posted this question on SO but figured it would be useful to have here as well...

Im sure the solution is blindingly obvious but any ideas on how i would do the following with value injecter?

Say you have the following model:
public class Foo{
    public int BarId{get;set;}
    public Bar Bar{get;set;}
}

public class Bar{
    public int Id{get;set;}
    [Required]
    public string Description{get;set;}
}
and a view model that looks like this:
public class FooBarViewModel{
    public int BarId{get;set;}
    public bool EditMode{get;set;}
}
when i call InjectFrom<UnflatLoopValueInjection>() on the Foo object i only want the Foo.BarId property populated, not theFoo.Bar.Id property as well. I would like to if possible stop the Unflattening process from recursing through the whole object graph if an exact match to a property name is found at a shallower depth in the graph.

Ideally i would like to do this without resorting to explicitly ignoring properties and being able to do this by convention.
Jul 24, 2013 at 2:37 PM
if you have BarId on one side and Bar.Id on another side they will be matched as from BarId to Bar.Id
to stop or modify this behaviour you would have to digg into the source code (it's not very much code, so I recommend you to do that)
Jul 24, 2013 at 3:01 PM
OK cool, im currently digging into the code.

I think the root cause of the issue is that the Tunnelier class is activating an instance of the Bar object which has a required data annotation, how ever we are using EF and the Bar object is lazy loaded, so we only need a reference to BarID and the activated instance on the Foo.Bar property is causing validation issues due to a lack of the description property being injected (as its not present in the view model returned by the client).

So moving forward looks like i will need to implement my own custom injection rather than sub classing the UnflatLoopValueInjection as i would rather not add the the maintenance of the app by changing core code :)
Jul 24, 2013 at 4:18 PM
Ok, so having dug a bit deeper it was as i suspected trivial to do :)
    public class UnflatLoopValueInjectionUseExactMatchIfPresent : UnflatLoopValueInjection {
        protected override void Inject(object source, object target) {
            var targetProperties = target.GetProps().Cast<PropertyDescriptor>().AsQueryable();
            foreach (PropertyDescriptor sourceProp in source.GetProps()) {
                var prop = sourceProp;
                if (targetProperties.Any(p => p.Name == prop.Name)) {
                    //Exact match found
                    targetProperties.First(p => p.Name == prop.Name).SetValue(target, SetValue(sourceProp.GetValue(source)));
                }
                else {
                    //Fall back to UnflatLoopValueInjection
                    var endpoints = UberFlatter.Unflat(sourceProp.Name, target, t => TypesMatch(prop.PropertyType, t)).ToList();
                    if (!endpoints.Any()) {
                        continue;
                    }
                    var value = sourceProp.GetValue(source);
                    if (!AllowSetValue(value)) {
                        continue;
                    }
                    foreach (var endpoint in endpoints) {
                        endpoint.Property.SetValue(endpoint.Component, SetValue(value));
                    }
                }
            }
        }
    }
Cheers for the quick reply
Jul 24, 2013 at 4:20 PM
good job