24

当 AutoMapper 遇到一个已经被映射的对象时,它似乎会再次使用该对象,而不是尝试重新映射它。我相信它是基于.Equals().

我有一棵正在映射的树。所以,一个具有一些属性和子节点的节点。多个节点具有相同的 值.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();
    }
}
4

5 回答 5

10

现在有一个选项可以禁用缓存。

Mapper.CreateMap<Tag, Tag>();
var results = Mapper.Map<IList<Tag>, IList<Tag>>(source, opt => opt.DisableCache = true);
于 2015-03-23T16:05:58.243 回答
9

我在映射器上遇到了同样的问题,环顾四周,我发现了一个解决方案,通过添加

Mapper.Reset();

源博客(更正的 URL)

于 2013-01-15T08:30:07.507 回答
4

我也遇到同样的问题。当您映射同一个对象两次时不会发生这种情况 - 当您具有对象的树继承关系时会发生这种情况,并且树的两个位置存在相同的值(但具有不同的子值)映射项目的第二个实例时- 它使用第一个实例的子值,而不是重新评估子值应该是什么。

这是我的例子:

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 的第一个实例(即 source[0])及其所有子对象都是完美的

  • 标签 1 的第二个实例(即 source[1])具有第一个实例的所有子级 - 它不应该有任何子级

  • 标记 3 的第二个实例(即源 [2])没有任何子级 - 它应该有标记 4 作为子级

于 2012-09-28T09:18:57.457 回答
1

当 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 (所有内部映射表达式都会丢失)

于 2012-09-20T08:19:08.127 回答
0

您正在映射的树对象的 Equals 行为似乎不合适。

仅当“指定对象等于当前对象”时,该方法才应返回 true。- http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx

在您的情况下,您有两个树对象共享相同的 id,但显然,它们不是“相等的”,因为它们有不同的孩子。

我建议看看为什么 Equals 方法以这种方式被滥用,以及是否可以通过不覆盖 Equals 方法来获得所需的行为,而是使用不同的方法来检查具有更合适名称的树 id 字段,例如。TreeIdsAreEqual。

于 2012-10-12T14:43:14.407 回答