首页 > 解决方案 > 实体框架:使用本地对象设置导航属性(尚未保存到数据库中)

问题描述

我正在使用 Entity Framework 版本 6,需要在很短的时间内将数千个对象批量插入数据库。

因此我更改DbContext.Configuration.AutoDetectChangesEnabled为 false 并且仅SaveChanges在添加了许多项目后使用。

我们称它为实体,它Person自身有一个导航属性,例如Supervisor

现在我想将一个人添加到数据库中,并希望使用刚刚添加到上下文中的主管填充导航属性(只是本地,而不是在数据库中)之前的迭代。

由于性能原因,我只是在 200 万人之后调用 SaveChanges()。如果我在SaveChanges该列Supervisor始终为 NULL 之后查看数据库。如何添加导航属性?

奇怪的是,我的实体模型有四个导航属性,分别命名为 Supervisor1、和 。为什么实体模型会为一个数据库约束创建四个导航属性?Supervisor2Supervisor11Supervisor3

详细解释我的问题:这是我的 数据库结构。EntityFramework 创建这个模型

有一个循环来处理来自 csv 文件的数据:

     db.DbContext.Configuration.AutoDetectChangesEnabled = false; // for performance
    ///...    
    while (!parser.EndOfData)
    {                  
    // process data from a csv file with a name and a supervisorId             
        db.AddNewPerson(name, supervisorId);
    }
    db.SaveChanges();
    db.DbContext.Configuration.AutoDetectChangesEnabled = true;

这是数据访问层的方法:

public void AddNewPerson(string name, long? supervisorId)
    {
        var dbSetPerson = dbContext.Set<Person>();
        var newPerson = new Person(name);
        dbSetPerson.Add(newPerson);

        if (supervisorId != null)
        {
            var supervisor = dbSetPerson.Local.FirstOrDefault(x => x.PersonId == supervisorId); // first look if the supervisor was just processed in this loop
            if (supervisor == null)
                supervisor = dbSetPerson.FirstOrDefault(x => x.PersonId == supervisorId); // if the was no person found look in the database
            if (supervisor != null)
                newPerson.Person2 = supervisor;
        }
    }

提前谢谢你的帮助!

标签: c#entity-frameworkbulkinsert

解决方案


我认为你的问题是,实体在这个阶段没有存储到数据库中,并且 EF(代理)不知道它。您可以做的是在调用 StoreChanges() 之后附加它:

yourContext.Persons.Attach(justAddedPerson);

但是当你添加一些代码时,我可以给出更具体的答案。

更新 根据您的编辑(我猜 Id 是 int 而不是自动创建的)我会建议以下内容:

var persons = new List<Person>();
while (!parser.EndOfData)
{
    var person = new Person { Name = parser... }
    person.SupervisorId = parser...
    list.Add(person);
}

dbSet.AddRange(persons);

dbContext.SaveChanges();

首先进行解析,然后进行数据库操作。EF 足够聪明,可以在您不更改配置时设置导航属性,这不再是必需的,因为 AddRange() 应该比 Add() 快得多,因为它只调用一次 detectchanges。通过仅设置主管 ID,


推荐阅读