简体   繁体   English

保存具有多个父项的EF实例

[英]Saving an EF instance which has multiple parents

When mapping back from business logic objects to EF objects, one of the main problems I have is cases where the same instance has 2 parents: 从业务逻辑对象映射回EF对象时,我遇到的主要问题之一是同一个实例有2个父对象的情况:

在此输入图像描述

(Objects are yellow, properties are orange) (对象为黄色,属性为橙色)

In the business logic world, there is only one instance of the Tree object here (which appears as a child of multiple parents: Forest and Section) 在业务逻辑世界中,这里只有一个Tree对象的实例(它显示为多个父项的子项:Forest和Section)

When I map everything back into EF objects with AutoMapper, EF thinks there are 2 separate instances of tree (despite them having the same ID). 当我使用AutoMapper将所有内容映射回EF对象时,EF认为有两个独立的树实例(尽管它们具有相同的ID)。 It therefore creates a duplicate in the DB. 因此,它在DB中创建副本。

What is the correct way to manage this scenario so that both Forest and Section point to the same record of Tree in the DB? 管理此方案的正确方法是什么,以便Forest和Section指向DB中相同的Tree记录?

Do we have to go through and manually make sure everything is attached which might be considered a duplicate? 我们是否必须通过手动确保所有附件都被认为是重复的?

Unfortunatelly EF needs to get same instance of a Tree object to consider him as same during saving whole Forest graph (overriding of his equality members doesn't help), which is not how Automapper maps object graphs by default. 不幸的是,EF需要获取Tree对象的相同实例,以便在保存整个Forest图形时将其视为相同(覆盖其平等成员没有帮助),这不是Automapper默认情况下映射对象图形的方式。

But you can set up your Automapper configuration in the way it reuses existing instances during mapping: 但您可以按照映射期间重用现有实例的方式设置Automapper配置:

var config = new MapperConfiguration(cfg =>
{
   cfg.CreateMap<Tree, TreeEF>().PreserveReferences();
});

Than if you have in your bussines model Forest and Section having a child reference to the same instance of a Tree , this reference will be preserved and no duplicates will be created. 如果你的bussines模型中的ForestSection有一个对Tree的同一个实例的子引用,那么这个引用将被保留,并且不会创建重复项。

EDIT 编辑

class Program
{
    static void Main(string[] args)
    {
        var config = new MapperConfiguration(cfg =>
            {
                cfg.CreateMap<Forest, ForestEF>().PreserveReferences();
                cfg.CreateMap<Section, SectionEF>().PreserveReferences();
                cfg.CreateMap<Tree, TreeEF>().PreserveReferences();
            });

        var mapper = config.CreateMapper();

        var forest = new Forest();
        var section = new Section();
        var tree = new Tree();

        forest.Trees.Add(tree);
        forest.Sections.Add(section);
        section.Trees.Add(tree);

        var result = mapper.Map<Forest, ForestEF>(forest);

        Console.WriteLine(object.ReferenceEquals(result.Trees[0], result.Sections[0].Trees[0]));
        Console.ReadLine();
    }
}

public class Forest
{
    public IList<Tree> Trees { get; set; } = new List<Tree>();
    public IList<Section> Sections { get; set; } = new List<Section>();
}

public class Section
{
    public IList<Tree> Trees { get; set; } = new List<Tree>();
}

public class Tree
{
}

public class ForestEF
{
    public IList<TreeEF> Trees { get; set; } = new List<TreeEF>();
    public IList<SectionEF> Sections { get; set; } = new List<SectionEF>();
}

public class SectionEF
{
    public IList<TreeEF> Trees { get; set; } = new List<TreeEF>();
}

public class TreeEF
{
}

I believe that if you don't want duplicates here, both children must not only reference the ID but also the specific instance in memory so EF knows it should be the same record (navigation property). 我相信如果你不想在这里重复,那么两个孩子不仅必须引用ID而且还要引用内存中的特定实例,因此EF知道它应该是相同的记录(导航属性)。 Otherwise, you have to save the parent record first and then assign the key to each child after the fact. 否则,您必须先保存父记录,然后在事后将密钥分配给每个子记录。 If this isn't a GUID but an auto generated id, then you probably need to use the same reference. 如果这不是GUID而是自动生成的id,那么您可能需要使用相同的引用。

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM