AutoMapper:使用多个入口点映射对象图?

时间:2014-04-23 17:07:20

标签: c# .net mapping automapper

说我有以下3种类型:人,公司和资产。

  • 人物有一组资产。
  • 公司有一系列资产。
  • 资产没有参考资料。

使用这些定义,我创建了以下对象实例:

  • P引用了资产AaAb
  • 公司C引用了资产AbAc

请注意,AbP都引用了相同的对象实例C

现在,我对这些类型中的每一种都有2个定义,并且已经定义了它们之间的映射,例如:

Mapper.CreateMap<Db.Person, Schema.Person>();
Mapper.CreateMap<Db.Company, Schema.Company>();
Mapper.CreateMap<Db.Assets, Schema.Assets>();

如果我通过分别调用P两次来映射CMapper.Map(如下面的代码),我会得到两个独立的Ab对象实例,其中一个是PC的一部分。{/ p>

var mappedP = Mapper.Map<Schema.Person>(P);
var mappedC = Mapper.Map<Schema.Company>(C);

如何让AutoMapper同时映射PC“或使用映射对象的相同”上下文“,以便它不会创建{的映射版本{1}}两次,而是重用相同的实例?

编辑为了澄清,我正在使用Entity Framework从数据库中检索我的对象图。 由于数据的形状(即多个“根”对象),我需要多个数据库查询,但这不是问题,只要这些查询是针对相同的DbContext执行的,实体框架只实现每个对象一次。 /> 因此,这使得可以使用Person,Company和Asset检索如上所述的数据 - 这非常有效。

我仍然需要以适合从我的服务层返回的格式按下这个对象图,但在我这样做之前,我希望AutoMapper将整个对象图从“Db”实体映射到“Schema”实体,所以我可以使用“架构”对象来按摩数据 - 因此我的问题。

我知道一个解决方法是引入一个人工容器实体(在上面的示例中,使用Person和Company属性)作为要映射的新单个根对象。
但是,这需要为我要映射的多个“根”对象的每个组合提供额外的类定义,这不是很优雅 - 我想知道是否有更好的方法来映射这些对象图?

编辑2 有趣的是,在调用Ab的范围内,AutoMapper 已经只对映射一次对象的行为,并且每当遇到原始对象时重用相同的映射实例再次,
我怀疑它保留了已经映射的实例的映射上下文(或“缓存”)(显式地或在调用堆栈中的某个地方),并且在调用Mapper.Map()之前处理它。

如果有办法使这个映射上下文显式化(例如通过将其作为Mapper.Map()的参数提供),这将解决我的问题而不会有内存泄漏的风险(未引用的缓存实例将在映射上下文失去范围)。

2 个答案:

答案 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本身所做的事情,因为它不是常用的功能。

老实说,这是一个容易出错的代码,可能需要做很多工作才能做好。如果可以,我建议寻找替代解决方案。使用源对象的多个副本生活有多糟糕?