Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 自动映射:映射具有多个入口点的对象图?_C#_.net_Mapping_Automapper - Fatal编程技术网

C# 自动映射:映射具有多个入口点的对象图?

C# 自动映射:映射具有多个入口点的对象图?,c#,.net,mapping,automapper,C#,.net,Mapping,Automapper,假设我有以下三种类型:个人、公司和资产 个人拥有一系列资产 这家公司拥有一批资产 资产没有引用 使用这些定义,我创建了以下对象实例: PersonP引用了资产Aa和Ab 公司C引用了资产Ab和Ac 请注意,相同的对象实例Ab同时被p和C引用 var mappedP = Mapper.Map<Schema.Person>(P); var mappedC = Mapper.Map<Schema.Company>(C); 现在,我对每种类型都有2个定义,并定义了它们之

假设我有以下三种类型:个人、公司和资产

  • 个人拥有一系列资产
  • 这家公司拥有一批资产
  • 资产没有引用
使用这些定义,我创建了以下对象实例:

  • Person
    P
    引用了资产
    Aa
    Ab
  • 公司
    C
    引用了资产
    Ab
    Ac
请注意,相同的对象实例
Ab
同时被
p
C
引用

var mappedP = Mapper.Map<Schema.Person>(P);
var mappedC = Mapper.Map<Schema.Company>(C);
现在,我对每种类型都有2个定义,并定义了它们之间的映射,例如:

Mapper.CreateMap<Db.Person, Schema.Person>();
Mapper.CreateMap<Db.Company, Schema.Company>();
Mapper.CreateMap<Db.Assets, Schema.Assets>();
如何让AutoMapper“同时”映射
p
C
,或者使用映射对象的相同“上下文”,这样它就不会创建两次映射版本的
Ab
,而是重用相同的实例

编辑为了澄清,我使用实体框架从数据库中检索对象图。 由于数据的形状(即多个“根”对象),我需要多个数据库查询,但这不是一个问题,只要这些查询针对相同的DbContext执行,Entity Framework只对每个对象物化一次。
因此,这使得能够检索如上所述的个人、公司和资产形状的数据——这非常有效

我仍然需要以适合从我的服务层返回的格式对这个对象图进行处理,但在此之前,我希望AutoMapper将整个对象图从“Db”实体映射到“Schema”实体,这样我就可以使用“Schema”类型的对象对数据进行处理,这就是我的问题

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

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

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

听起来有点神经质!:-)你为什么要做到这一点

如果您要创建自己的资产价值解析程序

    public class AssestsValueResolver: IValueResolver
    {
        private Assests _assets;
    ...
    }
然后在每次映射到资产之前创建映射(这对性能来说并不理想!)

var resolver=new AssestsValueResolver();
Mapper.CreateMap()
.全体成员(
m=>m.ResolveUsing().ConstructedBy(()=>resolver));
您可以缓存资产,以便在映射到Person和Customer时重用相同的实例,并且应该使用相同的资产(您会通过ID链接它们吗?)

虽然这是一个潜在的解决方案(我没有尝试过),但我可以再次问一下,您为什么要实现这一点


您不能按ID逻辑关联同一资产吗?

这里的问题是,虽然您拥有相同的源资产,但在映射时正在创建新的目标资产。AutoMapper应该如何确切地知道您已经映射了该资产,并且它应该a)以某种方式在某处找到该资产,b)重用它

问题不在于识别您是否拥有相同的资产(即,使用ID或其他),而在于保留这些资产的缓存。缓存对象时,框架将保留对它们的引用,垃圾收集器将不会收集它们,并且会出现内存泄漏

因此,为了使这项工作正常进行,您需要在缓存中创建弱引用,以便可以查找对象以查看它们是否存在,并重用它们。。。如果他们不创造它们。这不是AutoMapper自己做的事情,因为它不是通常需要的功能


老实说,这是一个容易出错的代码,可能需要大量的工作才能正确。如果可以的话,我建议你寻找其他的解决方案。使用源对象的多个副本有什么不好?

请参阅我在OP中的第二个补充。目前,我已经解决了这个限制,将对象图切割成多个具有一个根的不相交图。在使用AutoMapper映射每个图形之后,我再次合并结果。这并不理想,但目前它仍然有效。@Astrotrain-是的,在同一个map调用中,它确实重用了同一个实例。事实上,这是人们普遍抱怨的行为,似乎没有一个好的方法来禁用它。你可以在这里找到很多关于这种行为的问题。我不确定我是否明白你的意思。。这基本上意味着您必须自己跟踪已经映射的对象,如果您已经这样做了,为什么还要麻烦再次映射它呢?
var resolver = new AssestsValueResolver();
Mapper.CreateMap<Db.Assets, Schema.Assets>()
                    .ForAllMembers(
                        m => m.ResolveUsing<AssestsValueResolver>().ConstructedBy(() => resolver ));