Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I disable AutoMapper reference cache?

I believe AutoMapper is using a cache when it is mapping lists of objects from one type to another. Take a look at the following code:

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            Mapper.CreateMap<Source, Destination>()
                       .ForMember(dest => dest.SomeOtherNumber, opt => opt.Ignore());

            Mapper.AssertConfigurationIsValid();

            var sourceList = new List<Source>();

            var s1 = new Source {SomeNumber = 10};
            var s2 = new Source {SomeNumber = 69};

            sourceList.Add(s1);
            sourceList.Add(s1);
            sourceList.Add(s1);
            sourceList.Add(s2);

            var destList = Mapper.Map<List<Source>, List<Destination>>(sourceList);

            destList[0].SomeOtherNumber = 100;

            destList.ForEach(x => Console.WriteLine("SomeNumber: {0}, SomeOtherNumber: {1}", x.SomeNumber, x.SomeOtherNumber));
            Console.ReadLine();
        }
    }


    public class Source
    {
        public int SomeNumber { get; set; }
    }

    public class Destination
    {
        public int SomeNumber { get; set; }
        public int SomeOtherNumber { get; set; }
    }

}

The output of the code shows that even though I set only the SomeOtherNumber of the first object in the destList list, the first three items have the same property value because they are referencing the same object reference. I would like to know if I can disable this behavior, so even if I have duplicate references in the source list, I will not have duplicate references in the destination list. Does this make sense?

Here's the ouput:

SomeNumber: 10, SomeOtherNumber: 100
SomeNumber: 10, SomeOtherNumber: 100
SomeNumber: 10, SomeOtherNumber: 100
SomeNumber: 69, SomeOtherNumber: 0
like image 894
BlakeH Avatar asked Jan 22 '13 18:01

BlakeH


People also ask

When should you not use AutoMapper?

If you have to do complex mapping behavior, it might be better to avoid using AutoMapper for that scenario. Reverse mapping can get very complicated very quickly, and unless it's very simple, you can have business logic showing up in mapping configuration.

Why do we need AutoMapper?

AutoMapper is used whenever there are many data properties for objects, and we need to map them between the object of source class to the object of destination class, Along with the knowledge of data structure and algorithms, a developer is required to have excellent development skills as well.

Is AutoMapper slow?

Reflection. Libraries that do runtime magic like AutoMapper or inversion of control (IoC) containers use Reflection, which by its very nature is slow.

What is AutoMapper configuration?

What is AutoMapper? AutoMapper is a simple library that helps us to transform one object type into another. It is a convention-based object-to-object mapper that requires very little configuration. The object-to-object mapping works by transforming an input object of one type into an output object of a different type.

Can AutoMapper map collections?

AutoMapper supports polymorphic arrays and collections, such that derived source/destination types are used if found.


1 Answers

I would say this is cannot be done with AutoMapper as the time being. The instance caching is built in pretty deep and currently it can't be turned off easily. Altough your use case is very strange... having the same source object multiple times in a list but you still want different destination objects is quite unusual in my point of view.

But it can be worked around with a pretty bad hack, because it will turn off instance caching globally and relies on the implementation details of AutoMapper so use it carefully. And if you still want to try it out the below mentioned solution is not working with Automapper 2.2.0 because of a bug which is only fixed in the development branch so you need to build AutoMapper from source or wait for the next release.

But nevertheless here are the details

The instance caching is handled by the TypeMapObjectMapperRegistry.CacheMappingStrategy [source] which like all the other ITypeMapObjectMapper implementation is a private class.

However the TypeMapObjectMapperRegistry.AllMappers field which should return all the ITypeMapObjectMapper is a public Func which can be overridden:

So add this code before the first usage of the Mapper class:

var baseMappers = TypeMapObjectMapperRegistry.AllMappers();
TypeMapObjectMapperRegistry.AllMappers = () => 
    baseMappers.Where(m => m.GetType().Name != "CacheMappingStrategy").ToArray();

Mapper.CreateMap<Source, Destination>();
like image 108
nemesv Avatar answered Oct 05 '22 10:10

nemesv