Подтвердить что ты не робот

Как заставить AutoMapper не кэшировать сопоставленные объекты?

Когда AutoMapper встречает объект, который уже был отображен, кажется, что он снова использует этот объект, вместо того, чтобы его повторно отображать. Я считаю, что это делается на основе .Equals().

У меня есть дерево, которое отображается. Итак, node с некоторыми свойствами и дочерними. Более одного из узлов имеют одинаковое значение .Equals(), поскольку оно основывается на свойстве Id. Дети узлов различны, и мне нужны эти повторные отображения, но они используют значение кешированной карты.

Есть ли способ отключить кеширование? Все, что я могу представить, это внедрение нового конвертера, но это полностью поражает цель использования AutoMapper.

Вот пример того, как воспроизводить.

void Main()
{
    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>();
    var results = Mapper.Map<IList<Tag>, IList<Tag>>(source);

    results.Dump();
}

public class Tag
{
    public int Id { get; set; }
    public string Name { get; set; }
    public IEnumerable<Tag> ChildTags { get; set; }

    public override bool Equals(Object obj)
    {
        if (obj == null)
        {
            return false;
        }

        var x = this;
        var y = (Tag)obj;

        return x.Id.Equals(y.Id);
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}
4b9b3361

Ответ 1

Теперь есть возможность отключить кеш.

Mapper.CreateMap<Tag, Tag>();
var results = Mapper.Map<IList<Tag>, IList<Tag>>(source, opt => opt.DisableCache = true);

Ответ 2

Я столкнулся с той же проблемой с картографом, оглядевшись, обнаружил, что решение для него, добавив

Mapper.Reset();

Исходный блог

Ответ 3

Я также получаю ту же проблему. Это не происходит, если вы дважды сопоставляете один и тот же объект - это происходит, когда у вас есть иерархия дерева объектов, и одно и то же значение существует в двух местах дерева (но с разными дочерними значениями) При сопоставлении второго экземпляра элемента - он использует дочерние значения первого экземпляра, вместо того, чтобы переоценивать значения дочерних значений.

Вот мой пример:

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);
}

В результате

  • первый экземпляр тега 1 (т.е. источник [0]), и все его дети являются совершенными

  • второй экземпляр тега 1 (т.е. источник [1]) имеет все дочерние элементы первого экземпляра - у него не должно быть детей

  • второй экземпляр тега 3 (т.е. источник [2]) не имеет детей - он должен иметь тег 4 как дочерний

Ответ 4

Когда AutoMapper встречает объект, который уже был отображен, он похоже, снова использует этот объект, вместо того, чтобы пытаться повторно отобразить его. я верьте, что это делается на основе .Equals()

Можете ли вы объяснить, почему и когда вы это видите?

После быстрого просмотра исходного кода я уверен, что для объектов нет кеша. Вот тест, который иллюстрирует это:

   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]

    }

Без вашего кода трудно глубже проникнуть. Существует также метод Mapper.Reset(), который очищает MapperEngine и MapingConfiguration (все внутренние выражения отображения будут потеряны)

Ответ 5

Похоже, что поведение Equals, которое вы сопоставляете, является неуместным.

Метод должен возвращать только true, если "указанный объект равен текущему объекту". - http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx

В вашем случае у вас есть два дерева объектов, имеющих один и тот же идентификатор, но ясно, что они не являются "равными", поскольку у них разные дети.

Я предлагаю посмотреть, почему метод Equals был подвергнут насилию таким образом, и можете ли вы получить нужное поведение, не переопределяя метод Equals, вместо этого используя другой метод для проверки поля идентификатора дерева с более подходящим именем, например, TreeIdsAreEqual.