Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • James Kahler 36 posts 78 karma points
    Sep 12, 2014 @ 13:02
    James Kahler
    0

    Mapping collection custom mapper

    I'm trying to map a collection of Ipublishedcontent which is media. I've got a custom mapper for media types which maps to my custom media model.

    The problem i'm having is that when a collection of ipublishedcontent is mapped to a list of a type which has a custom mapper assigned umbraco mapper doesn't check for custom mappings.

    Custom mapping only seem to be check for in the map method.

    Hope this makes sense?

    Is this by design or could this be added?

  • Andy Butland 422 posts 2333 karma points MVP 4x hq c-trib
    Sep 12, 2014 @ 21:41
    Andy Butland
    0

    Hi James

    Yes, makes sense, but you should find custom mappings are picked up for mapping collections as well as when mapping from single instances of IPublishedContent - we've certainly used it with that scenario.  You can see from the code here that the call to map a collection simply iterates that collection and then calls the same method as used for a single instance - at which point the custom mappings you've registered should be picked up.  There's a unit test too to verify this.

    If you can post the relevant parts of your code somewhere happy to take a look.

    Cheers

    Andy

  • James Kahler 36 posts 78 karma points
    Sep 15, 2014 @ 12:06
    James Kahler
    0

    Thanks for the quick reply Andy

    I had a look at the unit test, it is slightly different to my scenario.

    for example:-

    var mapper = new UmbracoMapper();    
    mapper.AddCustomMapping(typeof(Media).FullName, MediaMapper.MapMediaFile);
    
    IEnumerable<IPublishedContent> mediaContent = Umbraco.TypedMedia(new string[] {"1234,1235,1236"});
    
    var model = new List<Media>();
    mapper.MapCollection(mediaContent,model);
    

    I want to map a collection of IPublishedContent to a collection of type that has a custom mapping. In your unit test the collection is inside an object. I could quite easily move my collection inside an object but just seems like i'm creating an object for the sake of it.

    Just for reference i'm mapping from macro parameters so slightly different from the normal setup.

  • Andy Butland 422 posts 2333 karma points MVP 4x hq c-trib
    Sep 15, 2014 @ 17:57
    Andy Butland
    0

    I see what you mean now James.  Yes, the mapping code loops through all the properties of the object you are mapping to, and checks the type of each of those for custom mappings.  It doesn't check the type of the object itself.

    Not come across this yet - I think even if my view model was only a single collection, I'd still look to make a particular view model class for it.  Just for naming conventions if nothing else, so I'd have a MediaGalleryViewModel containing an IEnumerable<Media> property or something similar.  So you could do that as you say, but there might be an easy way to update the code to get this to work as you have it.  I'll take a look and update later.

  • Andy Butland 422 posts 2333 karma points MVP 4x hq c-trib
    Sep 15, 2014 @ 18:34
    Andy Butland
    0

    Could you post your implementation of MediaMapper.MapMediaFile please James? 

  • James Kahler 36 posts 78 karma points
    Sep 16, 2014 @ 13:57
    James Kahler
    0

    It's the same implementation as your damp custom map i've just added a couple of extra properties.

  • Andy Butland 422 posts 2333 karma points MVP 4x hq c-trib
    Sep 16, 2014 @ 21:41
    Andy Butland
    0

    UPDATE 21/9/14 - removed dll as have now added to 1.4.9 (see comment below).

    I've put up an updated dll here James - let me know if this works for you and if so I'll publish the code/update the NuGet package etc.

    Seems to work fine in my tests.  The only change I've made is this in the MapCollection method:

        foreach (var content in contentCollection)
        {
            var itemToCreate = new T();
    
            // Check for custom mappings for the type itself (in the Map() method we'll check for custom mappings on each property)
            // - Any custom mappings used here cannot be based on a single property, as we don't have a property to map to to work out what this should be.
            //   So we just pass an empty string into the custom mapping call.
            var customMappingKey = itemToCreate.GetType().FullName;
            if (_customMappings.ContainsKey(customMappingKey))
            {
                itemToCreate = _customMappings[customMappingKey](this, content, string.Empty, false) as T;
            }
            else 
            {
                // Otherwise map the single content item as normal
                Map(content, itemToCreate, propertyMappings, recursiveProperties, propertySet);
            }
    
            modelCollection.Add(itemToCreate);
        }
    

     As the comment says, in this case as we are mapping object to object rather than IPublishedContent field to object property, the custom mapping method itself must "know" what property or properties to use. as we can't pass one.  So I'm just passing an empty string for that parameter.  Seems to work OK so hope you don't mind testing it out before I publish it in case I've missed something obvious.

    Cheers

    Andy

  • Andy Butland 422 posts 2333 karma points MVP 4x hq c-trib
    Sep 21, 2014 @ 23:01
    Andy Butland
    0

    I've added this code to version 1.4.9 of Umbraco Mapper James, if you or anyone else coming across this post requires this functionality.

    Andy

  • James Kahler 36 posts 78 karma points
    Sep 22, 2014 @ 14:37
    James Kahler
    0

    Sorry for the delay in getting back, What i found was my custom mapper would have to be slightly adapted because if there was an empty string passed it would need to use the contentToMapFrom instead of finding a property from contentToMapFrom. So what i did was to do a check for _customObjectMappings (I already had a custom object mapping setup) which worked straight away. I just thought this was a more practical way because you are passing objects.

    if (_customObjectMappings.ContainsKey(customMappingKey))
    {
       itemToCreate = (T)_customObjectMappings[customMappingKey](this, content);
    }
    else
    {
       // Otherwise map the single content item as normal
       Map(content, itemToCreate, propertyMappings, recursiveProperties, propertySet);
    } 
    
  • Andy Butland 422 posts 2333 karma points MVP 4x hq c-trib
    Sep 22, 2014 @ 22:44
    Andy Butland
    0

    Yes, very true - I didn't like that passing of the empty string, but couldn't see how to use an existing custom mapping without passing something. Even though in this scenario (without a model property, rather a whole model, for mapping) I couldn't avoid providing something for this parameter.  But the custom object mapping would work for this as you have done.  This wasn't really the intention of these - they were for use when mapping from a dictionary rather than IPublishedContent - but I can't see a good reason not to support what you've done.

    So have added to 1.4.10.

    Thanks for the question... and the solution!

    Andy

Please Sign in or register to post replies

Write your reply to:

Draft