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

时间:2017-11-17 12:07:35

标签: c# .net entity-framework entity-framework-6 automapper

当从业务逻辑对象映射回EF对象时,我遇到的一个主要问题是同一个实例有2个父对象的情况:

enter image description here

(对象为黄色,属性为橙色)

在业务逻辑世界中,这里只有一个Tree对象的实例(它显示为多个父项的子项:Forest和Section)

当我使用AutoMapper将所有内容映射回EF对象时,EF认为有两个独立的树实例(尽管它们具有相同的ID)。因此,它会在数据库中创建副本。

管理此方案的正确方法是什么,以便Forest和Section指向数据库中相同的Tree记录?

我们是否必须通过并手动确保所有内容都被附加,这可能被视为重复?

2 个答案:

答案 0 :(得分:2)

不幸的是,EF需要获取Tree对象的相同实例,以便在保存整个Forest图表时将其视为相同(覆盖其平等成员并不帮助),这不是怎么回事Automapper默认映射对象图。

但您可以按照映射期间重用现有实例的方式设置Automapper配置:

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

如果您的商务模型ForestSection具有对Tree的同一实例的子引用,则此引用将被保留,并且不会创建重复项。

修改

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
{
}

答案 1 :(得分:1)

我相信如果你不想在这里重复,那么两个孩子不仅要引用ID而且还要引用内存中的特定实例,这样EF就知道它应该是相同的记录(导航属性)。否则,您必须先保存父记录,然后在事后将密钥分配给每个子记录。如果这不是GUID而是自动生成的id,那么您可能需要使用相同的引用。