3

I am working with Umbraco 4.7.1 and I am trying to map the content-nodes to some autogenerated strong typed objects. I have tried using both valueinjecter and automapper, but OOTB neither of them map my properties. I guess it is because all properties on an Umbraco node (the cms document) are retrieved like this:

node.GetProperty("propertyName").Value;

And my strongly typed objects are in the format of MyObject.PropertyName. So how do I map the property on the node which is retrieved using a method and a string beginning with a lowercase character into a property on MyObject where the property begins with an uppercase character ?

UPDATE I managed to create the following code which maps the umbraco node as intended, by digging around in the Umbraco sourcecode for some inspiration on how to cast string-properties to strongly typed properties:

    public class UmbracoInjection : SmartConventionInjection
{
    protected override bool Match(SmartConventionInfo c)
    {
        return c.SourceProp.Name == c.TargetProp.Name;
    }

    protected override void Inject(object source, object target)
    {
        if (source != null && target != null)
        {

            Node node = source as Node;

            var props = target.GetProps();
            var properties = node.Properties;

            for (int i = 0; i < props.Count; i++)
            {
                var targetProperty = props[i];
                var sourceProperty = properties[targetProperty.Name];
                if (sourceProperty != null && !string.IsNullOrWhiteSpace(sourceProperty.Value))
                {
                    var value = sourceProperty.Value;
                    var type = targetProperty.PropertyType;
                    if (targetProperty.PropertyType.IsValueType && targetProperty.PropertyType.GetGenericArguments().Length > 0 && typeof(Nullable<>).IsAssignableFrom(targetProperty.PropertyType.GetGenericTypeDefinition()))
                    {
                        type = type.GetGenericArguments()[0];
                    }
                    targetProperty.SetValue(target, Convert.ChangeType(value, type));
                }
            }
        }
    }
}

As you can see I use the SmartConventionInjection to speed things up. It still takes approximately 20 seconds to map something like 16000 objects. Can this be done even faster ?

thanks

Thomas

ThomasD
  • 2,464
  • 6
  • 40
  • 56

1 Answers1

3

with ValueInjecter you would do something like this:

public class Um : ValueInjection
{
    protected override void Inject(object source, object target)
    {
        var node = target as Node;
        var props = source.GetProps();
        for (int i = 0; i < props.Count; i++)
        {
            var prop = props[i];
            target.GetProperty(prop.Name).Value;

        }
    }
}
Omu
  • 69,856
  • 92
  • 277
  • 407
  • thanks. When I try to set the value on the target, I get the error: Object of type 'System.String' cannot be converted to type 'System.Nullable`1[System.Int32]. Any help is appreciated. Thanks – ThomasD Apr 18 '12 at 13:28
  • I didn't posted the entire code, but basically what the message suggests is that you are trying to set a string property with a int? value, you can see that I'm matching properties just by name by doing target.GetProperty(prop.Name) but I don't check for type or anything, so you need to do that if you have props that are of the same name but different types – Omu Apr 18 '12 at 13:34
  • Hi. The names of the properties are unique and all the values on the source-node are stored as strings. How do I cast my source-property to the correct target propery-type ? I am new to all this reflection-stuff, so sorry about what might be a simple question – ThomasD Apr 18 '12 at 13:38
  • it's quite easy, you should figure out with intellisense, I don't know the umbraco stuff, but for the normal objects you can do this `var sourceValue = prop.GetValue(source);` – Omu Apr 18 '12 at 13:49
  • Thanks. I couldn't get it to work though. The thing is that the Umbraco values are all strings. But the autogenerated objects, that I am trying to map the properties to are different types. Eg. I might have a property like Node.Price = "54" and on the strongtyped object Object.Price is an int. Is it possible to infer that type from the strongly typed object and then cast the string value from the node before assigning it to the strongtyped object ? Thanks – ThomasD Apr 18 '12 at 17:25
  • you could do something like a big switch or if else `if (prop.PropertyType == typeof(int)) strval = sourceValue.ToString() else if ...` – Omu Apr 18 '12 at 17:33
  • I managed to cast the properties by looking at the umbraco source code. I have updated the question above because I would like to improve performance. Can you help ? Thanks – ThomasD Apr 20 '12 at 08:32
  • Thanks. I tried finding the documentation for HyperDescriptor (as per the thread here: http://stackoverflow.com/questions/2786761/automapper-recursive), but I cannot find it on codeplex. Btw, thanks for the impressive support! – ThomasD Apr 20 '12 at 11:19
  • look here http://valueinjecter.codeplex.com/SourceControl/changeset/view/66250#837322 at the Start() method – Omu Apr 20 '12 at 12:15
  • Thanks. I managed to increase performance 4x on my dev-box. Haven't tested it on production yet – ThomasD Apr 25 '12 at 09:25