简体   繁体   English

如何让AutoMapper不缓存映射对象?

[英]How do I get AutoMapper to not cache mapped objects?

When AutoMapper encounters an object that's already been mapped, it seems to use that object again, instead of trying to re-map it. 当AutoMapper遇到已经映射的对象时,它似乎再次使用该对象,而不是尝试重新映射它。 I believe it does this based on .Equals() . 我相信它基于.Equals()来做到这一点。

I have a tree that's being mapped. 我有一棵正在映射的树。 So, a node with some properties, and children. 所以,一个具有一些属性的节点和子节点。 More than one of the nodes have the same value of .Equals() , because it's based off an Id property. 不止一个节点具有相同的.Equals()值,因为它基于Id属性。 The children of the nodes are different and I need those re-mapped, but it's using a cached map value. 节点的子节点是不同的,我需要重新映射,但它使用缓存的映射值。

Is there a way to turn the cached mapping off? 有没有办法关闭缓存的映射? All I can think of is implementing a new converter, but that totally defeats the purpose of using AutoMapper. 我能想到的只是实现一个新的转换器,但这完全违背了使用AutoMapper的目的。

Here is an example on how to reproduce. 这是一个如何重现的例子。

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

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

I've faced the same issue with the mapper, looking around i found that a solution for it, by adding 我遇到了与mapper相同的问题,环顾四周我找到了解决方案,通过添加

Mapper.Reset();

Source blog (corrected URL) 来源博客 (更正后的网址)

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 标签1的第一个实例(即源[0])及其所有子项都是完美的

  • the second instance of Tag 1 (ie source[1]) has all the children of the first instance - it should not have any children 标签1的第二个实例(即源[1])具有第一个实例的所有子节点 - 它不应该有任何子节点

  • the second instance of Tag 3 (ie source[2]) does not have any children - it should have Tag 4 as a child 标签3的第二个实例(即源[2])没有任何孩子 - 它应该将标签4作为孩子

When AutoMapper encounters an object that's already been mapped, it seems to use that object again, instead of trying to re-map it. 当AutoMapper遇到已经映射的对象时,它似乎再次使用该对象,而不是尝试重新映射它。 I believe it does this based on .Equals() 我相信它基于.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) 还有一个方法Mapper.Reset()清除MapperEngine和MapingConfiguration(所有内部映射表达式都将丢失)

It seems that the Equals behaviour of the tree object you're mapping is inappropriate. 看来您映射的树对象的Equals行为是不合适的。

The method should only return true if "the specified object is equal to the current object." 如果“指定的对象等于当前对象”,则该方法应仅返回true。 - http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx - 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. 在您的情况下,您有两个共享相同ID的树对象但很明显,它们不是“相等”,因为它们有不同的子项。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 AutoMapper,如何在映射对象之间保持引用? - AutoMapper, how to keep references between mapped objects? 在返回使用自动映射器映射的 DTO 时,如何为其分配子类类型的列表? - While returning a DTO which is mapped using automapper, how do I assign it a list of it's child class type? 如何对具有多个XmlElementAttributes的对象使用automapper? - How do I use automapper for objects with multiple XmlElementAttributes? 在这种情况下如何使用 c# AutoMapper 映射对象 - How do I map Objects in this scenario using c# AutoMapper Automapper - 从映射集合中排除一些对象 - Automapper - exclude some objects from mapped collection 如何让AutoMapper处理自定义命名约定? - How do I get AutoMapper to deal with a custom naming convention? AutoMapper:如何获取目标属性的名称 - AutoMapper: How do I get the name of the destination property 如何在AutoMapper中合并两个对象? - How do you merge two objects in AutoMapper? 如何在 Windows 中获取内存缓存? - How do I get the memory cache in Windows? 如何让 AutoMapper:忽略非映射属性,包括常规映射并使用 QueryableExtensions - How get AutoMapper to: ignore non mapped properties, include conventional mapping and work with QueryableExtensions
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM