How do I get AutoMapper to not cache mapped objects?

前端 未结 5 1753
不思量自难忘°
不思量自难忘° 2021-02-04 00:37

When AutoMapper encounters an object that\'s already been mapped, it seems to use that object again, instead of trying to re-map it. I believe it does this based on .Equal

相关标签:
5条回答
  • 2021-02-04 00:42

    It seems that the Equals behaviour of the tree object you're mapping is inappropriate.

    The method should only return true if "the specified object is equal to the current object." - http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx

    In your case, you have two tree objects sharing the same id but clearly, they are not "equal" since they have different children.

    I suggest looking at why the Equals method has been abused in this way and whether you could get the behaviour you need by not overriding the Equals method, instead using a different method to check the tree id field with a more appropriate name eg. TreeIdsAreEqual.

    0 讨论(0)
  • 2021-02-04 00:43

    I also get the same issue. It doesn't happen when you map the same object twice - it happens when you have a tree heirarcy of objects, and the same value exists in two places of the tree (but with different child values) When mapping the second instance of the item - it uses the child values of the first instance, instead of re-evaluating what the child values should be.

    Here is my example:

    class Tag { 
      int Id {get; set;}
      string Name {get; set;}
      IEnumerable<Tag> ChildTags  {get; set;}
    }
    
    public void Test()
    {
    var source =  new List<Tag>
                {
                    new Tag { Id = 1, Name = "Tag 1", ChildTags = new List<Tag>
                                {
                                    new Tag { Id = 2, Name = "Tag 2", ChildTags = new List<Tag> 
                                                {
                                                    new Tag {Id = 3, Name = "Tag 3"},
                                                    new Tag {Id = 4, Name = "Tag 4"}
                                                }
                                        }
                                }
                        },
                    new Tag { Id = 1, Name = "Tag 1" },
                    new Tag {
                            Id = 3, Name = "Tag 3", ChildTags = new List<Tag>
                                {
                                    new Tag {Id = 4, Name = "Tag 4"}
                                }
                        }
                };
    
    Mapper.CreateMap<Tag, Tag>()
        .ForMember(dest => dest.ChildTags,
            opt => opt.MapFrom(src => src.ChildTags));
    var result = Mapper.Map<IList<Tag>, IList<Tag>>(tags);
    }
    

    In the result

    • the first instance of Tag 1 (ie source[0]) and all of its children are perfect

    • the second instance of Tag 1 (ie source[1]) has all the children of the first instance - it should not have any children

    • the second instance of Tag 3 (ie source[2]) does not have any children - it should have Tag 4 as a child

    0 讨论(0)
  • 2021-02-04 00:55

    I've faced the same issue with the mapper, looking around i found that a solution for it, by adding

    Mapper.Reset();
    

    Source blog (corrected URL)

    0 讨论(0)
  • 2021-02-04 00:56

    When AutoMapper encounters an object that's already been mapped, it seems to use that object again, instead of trying to re-map it. I believe it does this based on .Equals()

    Can you explain why and when you see that ?

    After a quick look in the source code, I'm sure there is no cache for objects. Here is a test that illustrate this :

       public class CustomerSource
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public DateTime DateOfBirth { get; set; }
    
            public int NumberOfOrders { get; set; }
        }
    
        public class CustomerTarget
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public DateTime DateOfBirth { get; set; }
    
            public int NumberOfOrders { get; set; }
        }
    
        [TestMethod]
        public void Test_AutoMapper()
        {
            Mapper.CreateMap<CustomerSource, CustomerTarget>();
    
            var source = new CustomerSource() { DateOfBirth = DateTime.Now, FirstName = "FirstName", LastName = "LastName", NumberOfOrders = int.MaxValue };
    
            var res1 = Mapper.Map<CustomerSource, CustomerTarget>(source);
            Console.WriteLine(res1.FirstName); // PRINT FirstName
    
            source.FirstName += "[UPDATED]";
            source.LastName += "[UPDATED]";
    
            var res2 = Mapper.Map<CustomerSource, CustomerTarget>(source);
            Console.WriteLine(res1.FirstName); // PRINT FirstName[UPDATED]
    
        }
    

    Without your code, it is difficult to go more deeply. There is also a method Mapper.Reset() that clears the MapperEngine and the MapingConfiguration (all internal mapping expressions will be lost)

    0 讨论(0)
  • 2021-02-04 00:59

    There is now an option to disable the cache.

    Mapper.CreateMap<Tag, Tag>();
    var results = Mapper.Map<IList<Tag>, IList<Tag>>(source, opt => opt.DisableCache = true);
    
    0 讨论(0)
提交回复
热议问题