当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();
}
}
答案 0 :(得分:10)
现在有一个禁用缓存的选项。
Mapper.CreateMap<Tag, Tag>();
var results = Mapper.Map<IList<Tag>, IList<Tag>>(source, opt => opt.DisableCache = true);
答案 1 :(得分:8)
答案 2 :(得分: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的第一个实例(即来源[0])及其所有孩子都很完美
标签1的第二个实例(即source [1])拥有第一个实例的所有子节点 - 它不应该有任何子节点
标签3的第二个实例(即来源[2])没有任何子女 - 它应该将标签4作为一个孩子
答案 3 :(得分: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(所有内部映射表达式都将丢失)
答案 4 :(得分:0)
您正在映射的树对象的Equals行为似乎不合适。
如果“指定的对象等于当前对象”,该方法应该只返回true。 - http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx
在您的情况下,您有两个共享相同ID的树对象但很明显,它们不是“平等”,因为它们有不同的子项。
我建议查看为什么Equals方法以这种方式被滥用,以及是否可以通过不覆盖Equals方法获得所需的行为,而是使用不同的方法来检查具有更合适名称的树id字段,例如。 TreeIdsAreEqual。