说我有以下3种类型:人,公司和资产。
使用这些定义,我创建了以下对象实例:
P
引用了资产Aa
和Ab
C
引用了资产Ab
和Ac
。请注意,Ab
和P
都引用了相同的对象实例C
。
现在,我对这些类型中的每一种都有2个定义,并且已经定义了它们之间的映射,例如:
Mapper.CreateMap<Db.Person, Schema.Person>();
Mapper.CreateMap<Db.Company, Schema.Company>();
Mapper.CreateMap<Db.Assets, Schema.Assets>();
如果我通过分别调用P
两次来映射C
和Mapper.Map
(如下面的代码),我会得到两个独立的Ab
对象实例,其中一个是P
和C
的一部分。{/ p>
var mappedP = Mapper.Map<Schema.Person>(P);
var mappedC = Mapper.Map<Schema.Company>(C);
如何让AutoMapper同时映射P
和C
“或使用映射对象的相同”上下文“,以便它不会创建{的映射版本{1}}两次,而是重用相同的实例?
编辑为了澄清,我正在使用Entity Framework从数据库中检索我的对象图。 由于数据的形状(即多个“根”对象),我需要多个数据库查询,但这不是问题,只要这些查询是针对相同的DbContext执行的,实体框架只实现每个对象一次。 /> 因此,这使得可以使用Person,Company和Asset检索如上所述的数据 - 这非常有效。
我仍然需要以适合从我的服务层返回的格式按下这个对象图,但在我这样做之前,我希望AutoMapper将整个对象图从“Db”实体映射到“Schema”实体,所以我可以使用“架构”对象来按摩数据 - 因此我的问题。
我知道一个解决方法是引入一个人工容器实体(在上面的示例中,使用Person和Company属性)作为要映射的新单个根对象。
但是,这需要为我要映射的多个“根”对象的每个组合提供额外的类定义,这不是很优雅 - 我想知道是否有更好的方法来映射这些对象图?
编辑2
有趣的是,在调用Ab
的范围内,AutoMapper 已经只对映射一次对象的行为,并且每当遇到原始对象时重用相同的映射实例再次,
我怀疑它保留了已经映射的实例的映射上下文(或“缓存”)(显式地或在调用堆栈中的某个地方),并且在调用Mapper.Map()
之前处理它。
如果有办法使这个映射上下文显式化(例如通过将其作为Mapper.Map()
的参数提供),这将解决我的问题而不会有内存泄漏的风险(未引用的缓存实例将在映射上下文失去范围)。
答案 0 :(得分:1)
听起来有点心理! :-)你为什么要实现这个目标?
如果您要创建自己的AssestsValueResolver
public class AssestsValueResolver: IValueResolver
{
private Assests _assets;
...
}
然后每次在映射到Assests之前创建地图(不适合性能!)
var resolver = new AssestsValueResolver();
Mapper.CreateMap<Db.Assets, Schema.Assets>()
.ForAllMembers(
m => m.ResolveUsing<AssestsValueResolver>().ConstructedBy(() => resolver ));
您可以缓存资产,以便在映射到Person和Customer时同时重复使用相同的实例,并且应该使用相同的资产(您是否可以通过ID链接它们?)。
虽然这可能是一个解决方案(我没试过),但我可以再问一下为什么要实现这个目标吗?
您是否可以按ID逻辑关联同一资产?
答案 1 :(得分:1)
您遇到的问题是,当您拥有相同的源资产时,您将在映射时创建新的目标资产。 AutoMapper到底应该知道你已经映射了这个资产,它应该a)以某种方式在某个地方找到这个资产,并且b)重用它?
问题并非在于确定您拥有相同的资产(即使用ID或其他内容),而是保留这些资产的缓存。当您缓存对象时,框架会保留对它们的引用,然后垃圾收集器将不会收集它们,并且您将有内存泄漏。
因此,为了使其工作,您需要在缓存中创建弱引用,以便您可以查找对象以查看它们是否存在,并重用它们......如果它们不创建它们。这不是AutoMapper本身所做的事情,因为它不是常用的功能。
老实说,这是一个容易出错的代码,可能需要做很多工作才能做好。如果可以,我建议寻找替代解决方案。使用源对象的多个副本生活有多糟糕?